想要保护APK应用内的代码逻辑安全,需要做一定的APK加固操作。加固的常见操作有:

  • 混淆
  • 加密
  • 隐藏
  • 检测
  • ...

如果采用第三方的加固服务,如360加固、腾讯乐固等,厂商无非是把一系列的混淆、加密、隐藏、检测等技术组合起来,封装好给你使用。

防止APK被调试

加壳

APK包加壳是一种常见的应用保护方法,通过在APK包外层添加一层保护壳,以防止逆向工程和调试。这种技术主要用于保护应用的代码和资源不被轻易破解和篡改。以下是APK包加壳的基本原理:

  1. 壳代码注入:

    加壳工具会在原始APK包中注入壳代码。这个壳代码通常是一个启动器,它在应用启动时首先运行,负责初始化和解密真正的应用代码。

  2. 加密原始代码和资源:

    原始APK包中的代码和资源文件会被加密。加密算法可以是对称加密(如AES)或非对称加密(如RSA),以确保只有壳代码能解密这些资源。

  3. 壳代码加载和解密:

    当用户启动应用时,壳代码首先运行,它会解密原始APK包中的代码和资源,然后将解密后的代码加载到内存中运行。

  4. 动态加载:

    解密后的代码通常不会写回到磁盘上,而是直接加载到内存中执行。这种动态加载的方式可以防止静态分析工具从磁盘上读取解密后的代码。

代码混淆

使用ProGuardR8等工具对代码进行混淆,使反编译后的代码难以理解。

android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

检测调试器

在运行时检测调试器的存在。如果检测到调试器,应用可以采取相应的操作,如退出或显示警告。

public boolean isDebuggerConnected() {
return android.os.Debug.isDebuggerConnected();
} if (isDebuggerConnected()) {
// Exit or handle the detection
System.exit(0);
}

使用反调试技术

利用各种反调试技术,如检测调试端口、调试标志等。

public boolean isBeingDebugged() {
return (android.os.Debug.isDebuggerConnected() ||
android.os.Debug.waitingForDebugger());
} if (isBeingDebugged()) {
// Exit or handle the detection
System.exit(0);
}

环境检测

检测应用运行的环境是否正常,如判断是否运行在模拟器上。

public boolean isEmulator() {
String brand = Build.BRAND;
String device = Build.DEVICE;
String model = Build.MODEL;
String product = Build.PRODUCT; return (brand.startsWith("generic") || device.startsWith("generic") ||
model.contains("google_sdk") || model.contains("Emulator") ||
product.equals("sdk") || product.equals("sdk_google"));
} if (isEmulator()) {
// Exit or handle the emulator detection
System.exit(0);
}

使用Native代码

将关键代码移到本地(native)层,用C/C++编写,并使用NDK编译。这样可以增加逆向工程的难度。

多层防护

结合以上多种方法,建立多层次的防护体系,增加破解和调试的难度。

防止APK被篡改

签名校验

签名就是给APK内的各个文件Hash,达到被人二次打包的时候能发现,那么原理是什么?

Android应用的签名机制经历了多次演变,主要包括V1、V2和V3签名方案。每一种签名方式都有不同的特点和应用场景:

V1 签名机制

已经被破解,是个不安全的签名。

V1签名(基于JAR签名,全版本都兼容)方式存在一些固有的缺陷,使得其在现代应用中被认为不够安全。以下是V1签名不安全的主要原因:

V1签名工作原理:

V1签名方式对APK包内的每个文件进行单独签名,并将这些签名信息存储在META-INF/MANIFEST.MF和META-INF/CERT.SF文件中。

  • MANIFEST.MF:包含每个文件的哈希值。
  • CERT.SF:包含MANIFEST.MF文件的哈希值,并由开发者的私钥签名。
  • CERT.RSA或CERT.DSA:包含签名证书和签名信息。

安全问题

  1. 无法保证整体完整性:

    V1签名只对单个文件进行签名,而不是对整个APK文件进行签名。因此,攻击者可以通过添加、删除或替换APK中的文件(如资源文件或DEX文件),而不会影响其他文件的签名完整性。

    例如,攻击者可以添加一个新的文件到APK中,而这个文件不会在MANIFEST.MF中被引用,从而绕过签名验证。

  2. 容易被重新打包:

    攻击者可以将APK文件解包、修改内容(如替换某些文件或添加恶意代码),然后重新打包并生成新的签名。这种方式可以完全替换原始签名,使用户难以发现APK已被篡改。

    V1签名方式的签名信息存储在 CERT.SF 和 CERT.RSA 文件中,这些文件本身也可以被攻击者修改或替换。

    签名文件篡改:

    如果签名文件(如CERT.SF和CERT.RSA)本身被错误地包含在签名范围内,那么攻击者可以通过篡改这些文件,生成新的签名信息并替换原始签名,从而使得原始签名失效。

    例如,攻击者可以生成新的签名证书和签名信息,替换CERT.RSA文件,使得整个签名验证过程基于攻击者的证书和签名信息。

V2 签名机制

V2签名(仅支持Android 7.0及以上版本)方案通过对整个APK文件进行签名,从而防止替换和篡改。它的工作原理如下:

  1. 整体签名

    V2签名方案对整个APK文件(除了签名块)进行签名,确保APK的完整性。具体步骤如下:

    1.1 生成APK签名块

    - 创建一个签名块,包含APK中所有文件的哈希值及其他签名信息。签名块位于APK文件的ZIP Central Directory之前,且不包括在签名计算范围内。

    1.2. 计算APK主体的哈希值

    - 计算APK主体(不包括签名块)的哈希值。此哈希值确保APK的内容在签名后不能被篡改。

    1.3. 签名信息

    - 使用开发者的私钥对上述哈希值进行签名,生成签名信息。该签名信息也存储在签名块中。

    1.4. 签名块结构

    - 签名块包含签名信息、证书、公钥等,保证签名的完整性和可验证性。

  2. 验证过程

    当设备安装APK文件时,系统会进行以下验证步骤:

    1. 读取签名块

      • 系统读取APK文件中的签名块,从签名块中提取签名信息、证书和公钥。
    2. 验证签名

      • 使用签名块中的公钥对签名信息进行验证,确保签名信息是由对应的私钥生成的。
    3. 验证哈希值

      • 计算APK主体(不包括签名块)的哈希值,并与签名块中存储的哈希值进行比较,确保APK主体未被篡改。
    4. 验证证书

      • 检查签名块中的证书是否有效,并与应用商店或预期的证书进行比对,确保签名的合法性。

防止替换和篡改的机制

V2签名方案通过以下机制防止APK被替换或篡改:

  1. 整体哈希值校验

    • 由于V2签名对整个APK文件(不包括签名块)进行哈希计算和签名,任何对APK文件的修改(例如增加、删除或替换文件)都会改变哈希值,导致签名验证失败。
  2. 签名块保护

    • 签名块位于APK文件的ZIP Central Directory之前,且不包括在签名计算范围内,因此签名块本身不会被篡改。任何对签名块之外部分的修改都会破坏签名完整性。
  3. 不可替换性

    • 签名块中的签名信息是由开发者的私钥生成的,只有拥有对应私钥的人才能生成有效的签名。篡改者无法生成与原始签名匹配的签名信息。
  4. 证书验证

    • 签名块中的证书可以用来验证签名的合法性,确保签名是由可信的开发者生成的。

V3 签名机制

在V2的基础上增加了版本控制和密钥轮换功能,进一步增强了安全性,但仅支持Android 9.0及以上版本。

动态完整性校验

定期对代码和数据进行校验,确保它们没有被篡改。

APK包的加固手段收集(浅)的更多相关文章

  1. Android动态方式破解apk终极篇(加固apk破解方式)

    一.前言 今天总算迎来了破解系列的最后一篇文章了,之前的两篇文章分别为: 第一篇:如何使用Eclipse动态调试smali源码 第二篇:如何使用IDA动态调试SO文件 现在要说的就是最后一篇了,如何应 ...

  2. JAVA获取apk包的package和launchable-activity名称(一)

    背景: 每次要获取apk包的package和launchable-activity名称都需要运行doc命令,感觉好浪费感情,因为经常记不住常常的路径,但又不想把aapt设置为环境变量 我这个工具分几步 ...

  3. Unity - Apk包的代码与资源提取

    最近在研究如何给Unity游戏进行加密,让别人不能轻易破解你的apk包,不过网上的加密方法都是有对应的破解方法~_~!!结果加密方法没找到好的,逆向工程倒会了不少.今天就来讲解如何提取一个没做任何保护 ...

  4. Android程序进行混淆,在导出签名apk包时出错!

    今天终于完成了近一个月的App开发工作,对程序进行混淆导出签名apk包时,却出现了如下的错误: Proguard returned with error code 1. See console Not ...

  5. 修改APK包并push到system/app路径下安装

    在工作中,经常遇到需要修改apk包里的资源文件,达到检验不同配置下程序运行情况的目的. 过程如下: 1.首先连接手机,进入命令行,输入:adb root,使得adb获取root权限. 2.输入:adb ...

  6. Android获取APK包名的几种方法

    Android获取APK包名的几种方法:1.adb shell pm list package -f | findstr 关键字 #只能获取到包名,主Activity名无法获取到 2.使用aapt-- ...

  7. UE4 减少APK包的大小

    本文依据官方文档 Reducing APK Package Size整理而来,不过我会陆续添加自己减少包大小的心得. ETC1 纹理 当使用ETC1打Android包时,注意ETC1是不会压缩带Alp ...

  8. 使用Android Studio打Andorid apk包的流程

    启动Android studio   1.点击菜单栏Build -> Generate Signed APK...,打开如下窗口 2.这里是类似eclipse中Android的签名,假设这里没有 ...

  9. php获取apk包信息的方法

    /*解析安卓apk包中的压缩XML文件,还原和读取XML内容 依赖功能:需要PHP的ZIP包函数支持.*/ include('./Apkparser.php'); $appObj = new Apkp ...

  10. 命令行创建Android应用,生成签名,对APK包签名并编译运行

    一.命令行创建Android应用 android create project -n HelloWorld -t android-22 -p HelloWorld1 -k org.crazyit.he ...

随机推荐

  1. linux获取docker容器中的文件路径怎么表示

    在Linux系统中,Docker容器中的文件路径与宿主机上的文件系统是隔离的,因此我们不能直接使用宿主机的文件系统路径来访问容器内的文件.但是,有几种方法可以让我们获取或操作Docker容器中的文件. ...

  2. .net formwork WebApi 跨域问题

    背景: ASP.NET Formwork  Api / ASP.Net Core Api  做比较. 有关  Global.asax.FilterConfig.cs 和 RouteConfig.cs ...

  3. 算法金 | 读者问了个关于深度学习卷积神经网络(CNN)核心概念的问题

    ​大侠幸会,在下全网同名[算法金] 0 基础转 AI 上岸,多个算法赛 Top [日更万日,让更多人享受智能乐趣] 读者问了个关于卷积神经网络核心概念的问题,如下, [问]神经元.权重.激活函数.参数 ...

  4. kettle从入门到精通 第六十四课 ETL之kettle kettle中执行SQL脚本步骤,使用需当心

    1.群里有不定时会有同学反馈执行SQL脚本步骤使用有问题,那么咱们今天一起来学习下该步骤.trans中的执行SQL脚本有两方面功能,使用时需小心,不然很容易踩坑. 官方定义: 翻译: 您可以使用此步骤 ...

  5. .NET5 ASP.NET CORE 发布到IIS 文件无法替换

    由于默认是:进程内托管.要在IIS里停止网站,才能替换文件. 建议解决方案是:进程外(out-of-process)托管 记事本修改项目的  .csproj 文件(或在VS上,选中web项目,右键-编 ...

  6. flutter 结合 springBoot 完成登录 注册 功能

    后端接口 前端调用接口代码 import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import '../page ...

  7. 燕千云 YQCloud 数智化业务服务管理平台 发布1.13版本

    2022年6月10日,燕千云 YQCloud 数智化业务服务管理平台发布1.13版本.本次燕千云1.13版本新增了远程桌面.知识库多人在线协作.移动端疫苗核酸信息管理.单据委托代理.技能管理.产品自助 ...

  8. 测试网络的小工具WinMTR

    ping网络的小工具 搜集了两个版本中文版和英文版 中文版---- WinMTR中文版.rarhttps://www.aliyundrive.com/s/bZqmokL5dTt提取码: k6v7 英文 ...

  9. Go语言中Kill子进程的正确姿势

    场景 我们在编写部署系统的时候,通常需要在机器上部署一个agent,用来执行部署脚本,为了防止部署脚本写的有问题,长时间hang住,我们通常会为脚本的执行设置一个超时时间,到了时间之后就kill掉该脚 ...

  10. 2>&1解释

    场景 /root/test.sh > runoob.log 2>&1 那2>&1是什么意思? 解释 将标准错误 2 重定向到标准输出 &1 ,标准输出 &am ...