注:本次学习来源于:52pojie的正己的《安卓逆向这档事》,部分知识来源于查资料或者chatgpt等ai
https://www.52pojie.cn/thread-1695141-1-1.html
https://github.com/ZJ595/AndroidReverse
https://aliyundrive.com/s/TJoKMK6du6x
关于校验
校验是一种验证或确认数据、信息或过程的准确性和完整性的过程。它通常用于确保数据在传输、存储或处理过程中没有发生错误或损坏。
校验可以采用多种方法,具体取决于需要校验的内容和目的。常见的校验方法包括校验和、哈希校验、冗余校验等。通过对数据进行校验,可以检测出任何可能的错误或篡改,并确保数据的正确性和可靠性。
在计算机领域,校验常用于网络通信、数据传输、文件下载、数据存储等场景中,以确保数据的完整性和准确性。此外,在软件开发中,校验也经常用于验证用户输入的数据是否符合要求,以防止错误或恶意输入对系统造成影响。
安卓中常见的校验有:签名校验(最常见)、dexcrc校验、apk完整性校验、路径文件校验等
什么是APK签名
APK签名是指对Android应用程序包(APK)进行数字签名,以验证应用程序的来源和完整性。当开发者准备发布应用程序时,他们会使用数字证书对APK文件进行签名。这个数字证书由开发者私钥生成,用于对应用程序进行加密签名,并附加到APK文件中。
APK签名有以下作用:
验证应用程序的来源:通过数字签名,用户可以验证应用程序是否来自特定的开发者或组织。
确保应用程序未被篡改:签名可以确保应用程序在发布后未经修改,从而保证应用程序的完整性。
提供数据完整性保护:签名可以确保应用程序在传输过程中未被篡改。
在用户安装应用程序时,Android操作系统会验证应用程序的签名并执行一系列安全检查,以确保应用程序的来源和完整性。如果应用程序的数字签名无效或与开发者声明的不匹配,系统将会发出警告或阻止应用程序的安装。这有助于保护用户免受恶意软件和篡改应用程序的影响。
Android 目前支持以下四种应用签名方案:
1 | v1 方案:基于 JAR 签名。 |
v1 方案:基于 JAR 签名
V1 签名的机制主要就在 META-INF 目录下的三个文件,MANIFEST.MF,CERT.SF,CERT.RSA,他们都是 V1 签名的产物。
(1)MANIFEST.MF:这是摘要文件。程序遍历Apk包中的所有文件(entry),对非文件夹非签名文件的文件,逐个用SHA1(安全哈希算法)生成摘要信息,再用Base64进行编码。如果你改变了apk包中的文件,那么在apk安装校验时,改变后的文件摘要信息与MANIFEST.MF的检验信息不同,于是程序就不能成功安装。
(2)CERT.SF:这是对摘要的签名文件。对前一步生成的MANIFEST.MF,使用SHA1-RSA算法,用开发者的私钥进行签名。在安装时只能使用公钥才能解密它。解密之后,将它与未加密的摘要信息(即,MANIFEST.MF文件)进行对比,如果相符,则表明内容没有被异常修改。
(3)CERT.RSA文:使用私钥计算SF文件的数字签名 + 包含公钥的证书。。
签名校验
如何判断是否有签名校验?
不做任何修改,直接签名安装,应用闪退则说明大概率有签名校验
一般来说,普通的签名校验会导致软件的闪退,黑屏,卡启动页等
1 | kill/killProcess-----kill/KillProcess()可以杀死当前应用活动的进程,这一操作将会把所有该进程内的资源(包括线程全部清理掉).当然,由于ActivityManager时刻监听着进程,一旦发现进程被非正常Kill,它将会试图去重启这个进程。这就是为什么,有时候当我们试图这样去结束掉应用时,发现它又自动重新启动的原因. |
普通获取签名校验代码:
1 | private boolean SignCheck() { |
闪退代码定位
方法1
使用算法助手,拦截应用退出与闪退
再查看日志
mt管理器搜索方法名,再注释exit调用即可
1 | .line 57 |
方法2
算法助手,开启:读取应用签名监听
将判断签名的函数的判断逻辑改了
比如:
1 | if-nez v3, :cond_4f 改为 if-eqz |
签名校验对抗方法
方法一:核心破解插件,不签名安装应用
方法二:一键过签名工具,例如MT、NP、ARMPro、CNFIX、Modex的去除签名校验功能
方法三:具体分析签名校验逻辑(手撕签名校验)
方法四:io重定向–VA&SVC:ptrace+seccomp
SVC的TraceHook沙箱的实现&无痕Hook实现思路
手动实现PM代理
什么是PMS
在安卓中,PMS是指“包管理服务”(Package Manager Service)。PMS是安卓操作系统中的一个核心组件,负责管理应用程序的安装、卸载、更新等操作,以及管理应用程序的权限。
PMS具有以下主要功能:
应用程序管理:PMS负责跟踪和管理安卓设备上安装的所有应用程序。它维护一个应用程序的列表,并管理应用程序的安装、卸载和更新。
权限管理:PMS负责应用程序的权限分配和管理。在安卓系统中,应用程序必须在安装时声明其所需的权限,PMS会验证这些权限并在运行时管理它们的分配。
包信息管理:PMS维护了关于每个应用程序的详细信息,包括应用程序的名称、版本号、作者、大小等信息。
应用程序的启动和停止:PMS负责启动、停止和管理运行在安卓设备上的应用程序。
应用程序数据的管理:PMS也涉及应用程序数据的管理,包括数据的备份和还原,以及数据的清除。
实现方法以及原理解析
思路源自:Android中Hook 应用签名方法
HOOK PMS代码:
1 | package com.zj.hookpms; |
ActivityThread的静态变量sPackageManager
ApplicationPackageManager对象里面的mPM变量
IO重定向
IO重定向可以干嘛?(实际就是hook了打开文件的函数)
1,可以让文件只读,不可写
2,禁止访问文件
3,路径替换
1 | using namespace std; |
其他常见校验
root检测:
反制手段
1.算法助手、对话框取消等插件一键hook
2.分析具体的检测代码
3.利用IO重定向使文件不可读
4.修改Andoird源码,去除常见指纹
常见检测代码:
1 | fun isDeviceRooted(): Boolean { |
定义了一个 isDeviceRooted()
函数,该函数调用了三个检测 root 的方法:checkRootMethod1()
、checkRootMethod2()
和 checkRootMethod3()
。
checkRootMethod1()
方法检查设备的 build tags
是否包含 test-keys
。这通常是用于测试的设备,因此如果检测到这个标记,则可以认为设备已被 root。
checkRootMethod2()
方法检查设备是否存在一些特定的文件,这些文件通常被用于执行 root 操作。如果检测到这些文件,则可以认为设备已被 root。
checkRootMethod3()
方法使用 Runtime.exec()
方法来执行 which su
命令,然后检查命令的输出是否不为空。如果输出不为空,则可以认为设备已被 root。
模拟器检测
1 | fun isEmulator(): Boolean { |
通过检测系统的 Build
对象来判断当前设备是否为模拟器。具体方法是检测 Build.FINGERPRINT
属性是否包含字符串 "generic"
。
更多检测代码:模拟器检测对抗
反调试检测
安卓系统自带调试检测函数
1 | fun checkForDebugger() { |
debuggable属性
1 | public boolean getAppCanDebug(Context context)//上下文对象为xxActivity.this |
ptrace检测:每个进程同时刻只能被1个调试进程ptrace ,主动ptrace本进程可以使得其他调试器无法调试
1 | int ptrace_protect()//ptrace附加自身线程 会导致此进程TracerPid 变为父进程的TracerPid 即zygote |
调试进程名检测
1 | int SearchObjProcess() |
frida检测
smali语法小课堂之赋值
Int型赋值
在Smali汇编语言中,”const/4”和”const/16”是用于将常量加载到寄存器中的指令。
“const/4”指令:这个指令将一个常量值加载到4位宽度的寄存器中。它适用于范围在0-15之间的常量值。例如,”const/4 v0, 5”将常量值5加载到寄存器v0中。
“const/16”指令:这个指令将一个常量值加载到16位宽度的寄存器中。它适用于范围在-32768到32767之间的常量值。例如,”const/16 v1, -100”将常量值-100加载到寄存器v1中。
区别在于加载的常量值的范围和寄存器的宽度。由于”const/4”使用较小的寄存器宽度,它可以用于加载较小的常量值,而”const/16”则可以用于更大范围的常量值。选择适当的指令取决于您要加载的常量值的大小范围。
Long型赋值
1 | const-wide v0, 0x1854460ef29L |
在Smali汇编语言中,”const-wide”指令用于将一个64位的常量值加载到寄存器中。其中,”const-wide v0, 0x1854460ef29L”表示将十六进制值0x1854460ef29L加载到寄存器v0中。
具体解析如下:
- “const-wide”指令用于加载64位的常量值。
- “v0”是目标寄存器,表示将常量值加载到寄存器v0中。
- “0x1854460ef29L”是一个64位的十六进制常量值,在这种情况下表示为长整型。注意,常量值以大写字母”L”结尾,以指示它是长整型。