apk加壳去壳

本文详细介绍了Android APK的加壳和去壳过程,包括基础原理和操作步骤。基础原理涉及DEX头内容的修改,操作过程涵盖源APK的处理、加密和拼接工具的使用,以及自定义Application和DEX替换等关键环节。通过加壳技术,可以增强APP的安全性,隐藏源代码。
摘要由CSDN通过智能技术生成

1.1原理

(1)基础原理

在这里插入图片描述
在整个加固过程中,我们会涉及到四个文件(其实最终要实现加固,需要涉
及的文件不止四个,这里我们仅包含了主要文件):

  • originalAPK.apk:APK 文件,也就是我们要加固的 APP
  • shellDex.dex:dex 文件,该文件的程序功能是将 originalAPK.apk 的密文
    进行解密,并将 originalAPK.apk 中的 dex 文件进行加载,启动被加固的 APP。
    该 dex 文件来自于一个 APK 文件,我们称为 shellAPK.apk。注意,在
    shellAPK.apk 中,shellDex.dex 文件的名字为 classes.dex。这里,我们为了区
    别,将其改名为 shellDex.dex。
  • addShell.java:java 程序,用来加密 originalAPK.apk,并将
    originalAPK.apk 密文与 shellDex.dex 文件合并,生成 classes.dex 文件,并将该
    文件加入到 shellAPK.apk 中替换原来的 classes.dex 文件。
  • classes.dex:dex 文件,最终到用户手里的 shellAPK.apk 中的 dex 文件,
    该文件本质上包含 shellAPK.apk 中原 classes.dex 文件和 originalAPK.apk 的密
    文。

一般加固流程
1.生成 originalAPK.apk
2.编写 addShell.java 程序(注:虽然这里没有所要操作的 shellDex.dex 文件,
但其文件格式都已知晓,不会影响程序的实现)
3.编写 shellAPK.apk,并从中提取 classes.dex 文件改名为 shellDex.dex(注:
虽然这里 originalAPK.apk 都没有被加密,也没有与 shellDex.dex 合并,但解密
算法和文件格式都已知晓,不会影响程序的实现)
4.运行 addShell.java 程序,生成 classes.dex
5.修改相关文件,如 Manifest 文件,将修改后的文件和第四步生成的
classes.dex 文件替换 shellAPK.apk 中相应的文件。最终获得的 shellAPK.apk 就
是我们加固后的 originalAPK.apk。

(2)DEX 头内容

在这里插入图片描述
需要关注的字段:

  • checksum 文件校验码 ,使用 alder32 算法校验文件除去 maigc ,
    checksum 外余下的所有文件区域 ,用于检查文件错误 。
  • signature 使用 SHA-1 算法 hash 除去 magic ,checksum 和 signature 外余
    下的所有文件区域 ,用于唯一识别本文件 。
    ·- ileSize Dex 文件的大小 。
    在文件的最后,我们需要标注被加密的 apk 的大小,因此需要增加 4 个字
    节。

简单来说,我们将数据拼接后,还需要修改这三个字段,以保证文件正常运
行。最后,这个新 DEX 的结构大概如下
在这里插入图片描述
因此拼接步骤如下:
• 获取脱壳 DEX (二进制数据)
• 计算新 DEX 的大小(脱壳 DEX 的大小 + 加密 APK 的大小 + 4)
• 依次拼接脱壳 DEX、加密 APK、加密 APK 的大小,得到新 DEX
• 修改新 DEX 头的三个字段
• 输出新 DEX

1.2操作过程

(1)源apk

首先新建一个HelloWorld
MainAcitivity

public class MainActivity extends AppCompatActivity {
   

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("helloPack", "I am coming");
    }
}

(2)加密和拼接工具(函数)

使用 Android Studio 的 Java
Moudle 来编辑 Java 函数。
再明确一下功能:对源 APK 进行加密、拼接到脱壳 DEX,得到新 DEX。

1、新建 Java Moudle

新建工程,默认模板即可,然后右键 app,New -> Moudle -> Java Library:
在这里插入图片描述

此时,会生成一个 lib 文件夹和一个默认的 MyClass.java,我们可以在里面编辑 Java 代码。

在这里插入图片描述
这里测试一下:

public class MyClass {
   
 public static void main(String[] args) {
   
 System.out.println("hello Java");
 }
}

右键 MyClass,或者点击对应文件旁边的按钮,选择 Run"MyClass.main()":
在这里插入图片描述

2、 加密和拼接

package com.example.lib;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.Adler32;

public class MyClass {
   
    public static void main(String[] args){
   
        try {
   
            // 获取源APK(项目根目录下)
            File srcApkFile = new File("force/orignal.apk");
            System.out.println("apk path: " + srcApkFile.getAbsolutePath());
            System.out.println("apk size: " + srcApkFile.length());
            // 加密并返回数据
            byte[] enSrcApkArray = encrypt(readFileBytes(srcApkFile));
            // 脱壳DEX, 以二进制形式读出DEX
            File unShellDexFile = new File("force/classes.dex");
            System.out.println("unShellDexFile path: " + unShellDexFile.getAbsolutePath());
            System.out.println("unShellDexFile size: " + unShellDexFile.length());
            byte[] unShellDexArray = readFileBytes(unShellDexFile);

            // 将脱壳DEX长度和加密APK长度相加并加上存放加密APK大小的四位得到总长度
            int unShellDexLen = unShellDexArray.length;
            int enSrcApkLen = enSrcApkArray.length;
            // 多出的四位存放加密APK长度
            int totalLen = unShellDexLen + enSrcApkLen + 4;

            // 依次将脱壳DEX,加密APK,加密APK大小,拼接出新的DEX
            byte[] newDex = new byte[totalLen];
            // 复制加壳数据
            System.arraycopy(unShellDexArray, 0, newDex, 0, unShellDexLen);
            // 复制加密APK数据
            System.arraycopy(enSrcApkArray, 0, newDex, unShellDexLen, enSrcApkLen);
            // 赋值加密APK大小
            System.arraycopy(intToByte(enSrcApkLen), 0, newDex, totalLen - 4, 4);

            // 修改DEX file size 文件头
            fixFileSizeHeader(newDex);
            // 修改DEX SHA1 文件头
            fixSHA1Header(newDex);
            // 修改DEX CheckNum文件头
            fixCheckSumHeader(newDex);

            // 新DEX文件名
            String str = "force/classesShell.dex";
            File file = new File(str);
            if (!file.exists()) {
   
                if (!file.createNewFile()) {
   
                    System.out.println("File create error");
                    return;
                }
            }
            // 导出文件
            FileOutputStream fos = new FileOutputStream(str);
            fos.write(newDex);
            fos.flush();
            fos.close();
        } catch (IOException | NoSuchAlgorithmException e) {
   
            e.printStackTrace();
        }
    }

    /**
     * 修改DEX头,checkSum校验码
     * @param dexBytes 要修改的二进制数据
     */
    private static void fixCheckSumHeader(byte[] dexBytes) {
   
        Adler32 adler = new Adler32();
        // 从12到文件末尾计算校验码
        adler.update(dexBytes, 12, dexBytes.length - 12);
        long value = adler.getValue();
        int va = (int) value;
        byte[] newCs = intToByte(va);
        // 高低位互换位置
        byte[] reCs = new byte[4];
        for (int i = 0; i < 4; i++) {
   
            reCs[i] = newCs[newCs.length - 1 - i];
            System.out.println("fixCheckSumHeader:" + Integer.toHexString(newCs[i]));
        }
        // 校验码赋值(8-11)
        System.arraycopy(reCs, 0, dexBytes, 8, 4);
        System.out.println("fixCheckSumHeader:" + Long.toHexString(value));
    }

    /**
     * 修改DEX头, sha1值
     * @param dexBytes 要修改的二进制数组
     */
    private static void fixSHA1Header(byte<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值