Android逆向5-签名校验&smail
Android逆向5-签名校验&smail
来自吾爱破解-正己
https://www.52pojie.cn/thread-1701353-1-1.html
- 了解APK文件签名
- 了解APK常见校验及校验对抗方法
- 了解PM代{过}{滤}理和IO重定向
- smali语法之赋值
校验
常见的校验有:签名校验(最常见)、dexcrc校验、apk完整性校验、路径文件校验等
APK签名
通过对 Apk 进行签名,开发者可以证明对 Apk 的所有权和控制权,可用于安装和更新其应用。而在 Android 设备上的安装 Apk ,如果是一个没有被签名的 Apk,则会被拒绝安装。在安装 Apk 的时候,软件包管理器也会验证 Apk 是否已经被正确签名,并且通过签名证书和数据摘要验证是否合法没有被篡改。只有确认安全无篡改的情况下,才允许安装在设备上。
简单来说,APK 的签名主要作用有两个:
- 证明 APK 的所有者。
- 允许 Android 市场和设备校验 APK 的正确性。
Android 目前支持以下四种应用签名方案:
v1 方案:基于 JAR 签名。
v2 方案:APK 签名方案 v2(在 Android 7.0 中引入)
v3 方案:APK 签名方案 v3(在 Android 9 中引入)
v4 方案:APK 签名方案 v4(在 Android 11 中引入)
V1 签名的机制主要就在 META-INF 目录下的三个文件,MANIFEST.MF,ANDROID.SF,ANDROID.RSA,他们都是 V1 签名的产物。
MANIFEST.MF:这是摘要文件。程序遍历Apk包中的所有文件(entry),对非文件夹非签名文件的文件,逐个用SHA1(安全哈希算法)生成摘要信息,再用Base64进行编码。如果你改变了apk包中的文件,那么在apk安装校验时,改变后的文件摘要信息与MANIFEST.MF的检验信息不同,于是程序就不能成功安装。
ANDROID.SF:这是对摘要的签名文件。对前一步生成的MANIFEST.MF,使用SHA1-RSA算法,用开发者的私钥进行签名。在安装时只能使用公钥才能解密它。解密之后,将它与未加密的摘要信息(即,MANIFEST.MF文件)进行对比,如果相符,则表明内容没有被异常修改。
ANDROID.RSA文件中保存了公钥、所采用的加密算法等信息。
在某些情况下,直接对apk进行v1签名可以绕过apk的签名校验
v2方案会将 APK 文件视为 blob,并对整个文件进行签名检查。对 APK 进行的任何修改(包括对 ZIP 元数据进行的修改)都会使 APK 签名作废。这种形式的 APK 验证不仅速度要快得多,而且能够发现更多种未经授权的修改。
签名校验
如何判断是否有签名校验?不做任何修改,直接签名安装,应用闪退则说明大概率有签名校验
一般来说,普通的签名校验会导致软件的闪退,黑屏,卡启动页等
当然,以上都算是比较好的,有一些比较狠的作者,则会直接rm -rf /,把基带都格掉的一键变砖。
1 | kill/killProcess-----kill/KillProcess()可以杀死当前应用活动的进程,这一操作将会把所有该进程内的资源(包括线程全部清理掉).当然,由于ActivityManager时刻监听着进程,一旦发现进程被非正常Kill,它将会试图去重启这个进程。这就是为什么,有时候当我们试图这样去结束掉应用时,发现它又自动重新启动的原因. |
在我个人见过最恶心的签名校验中,当属三角校验(低调大佬教的)最烦人。
所谓三角校验,就是so检测dex,动态加载的dex(在软件运行时会解压释放一段dex文件,检测完后就删除)检测so,dex检测动态加载的dex
试验
对吾爱破解app进行v1签名安装,点击第五关,直接白屏
算法助手选中吾爱破解拦截应用退出及闪退
法1:
法2替换签名后的值
替换
普通:系统将应用的签名信息封装在 PackageInfo 中,调用 PackageManager 的 getPackageInfo(String packageName, int flags) 即可获取指定包名的签名信息
签名校验对抗
方法一:核心破解插件,不签名安装应用
方法二:一键过签名工具,例如MT、NP、ARMPro、CNFIX、Modex的去除签名校验功能
方法三:具体分析签名校验逻辑(手撕签名校验)
方法四:io重定向–VA&SVC:ptrace+seccomp
SVC的TraceHook沙箱的实现&无痕Hook实现思路
方法五:去作者家严刑拷打拿到.jks文件和密码
手动实现PM代{过}{滤}理
思路源自:Android中Hook 应用签名方法
https://www.52pojie.cn/forum.php?mod=viewthread&tid=1731203
PackageManagerService(简称PMS),是Android系统核心服务之一,处理包管理相关的工作,常见的比如安装、卸载应用等。
1 | MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYDVQQGEwJVUzET |
替换到下述代码中
有点过时
1 | package com.zj.hookpms; |
ActivityThread的静态变量sPackageManager
ApplicationPackageManager对象里面的mPM变量
IO重定向
什么是IO重定向?
例:在读A文件的时候指向B文件
Virtual Engine for Android(Support 12.0 in business version)
IO重定向可以干嘛?
- 可以让文件只读,不可写
- 禁止访问文件
- 路径替换
具体实现:
- 过签名检测(读取原包)
- 风控对抗(例:一个文件记录App启动的次数)
- 过Root检测,Xposed检测(文件不可取)
1 | sget-object p10, Lcom/zj/wuaipojie/util/ContextUtils;->INSTANCE:Lcom/zj/wuaipojie/util/ContextUtils; |
注意hash校验需联网
核心破解
不勾选自动签名无法安装
核心破解可以过掉一些(不勾选自动签名)
IO重定向源码:
1 | using namespace std; |
其他常见校验
root检测
反制手段
- 算法助手、对话框取消等插件一键hook
- 分析具体的检测代码
- 利用IO重定向使文件不可读
- 修改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 | int ptrace_protect()//ptrace附加自身线程 会导致此进程TracerPid 变为父进程的TracerPid 即zygote |
每个进程同时刻只能被1个调试进程ptrace ,主动ptrace本进程可以使得其他调试器无法调试
调试进程名检测
1 | int SearchObjProcess() |
frida检测
smali语法小课堂之赋值
int类型
1 | .method private static final onCreate$lambda-0(Lcom/zj/wuaipojie/ui/SmaliLearn;Landroid/widget/TextView;Landroid/widget/TextView;Landroid/widget/TextView;Landroid/view/View;)V |
const/4和const/16的区别?
const/4 最大只允许存放4个二进制位(4bit),
const/16 最大值允许存放16个二进制位(16bit), 第一位(即最高位)默认为符号位。单位换算 1byte=8bit
举例说明下寄存器的取值范围:
以下数据定义高位默认为符号位
const/4 v0,0x2 最大只允许存放半字节数据 取值范围为 -8 and 7
const/16 v0 , 0xABCD # 定义一个寄存器变量,最大只允许存放16位数据 比如short类型数据 取值范围为-32768~32767
const v0 , 0xA # 定义一个寄存器, 最大只允许存放32位数据,比如int类型数据 将数字10赋值给v0 取值范围-2147483647~2147483647
const/high16 #定义一个寄存器, 最大只允许存放高16位数值 比如0xFFFF0000末四位补0 存入高四位0XFFFF
Long类型
会员到期时间就是2022年12月24日。那么1854460ef29L 怎么来的呢?也就是(2022年12月24日-1970年1月1日)×365天×24小时×60分钟×60秒×1000毫秒,转换成16进制就大概是那个数了
变量赋值(正则)
1 | (.*) .* |
通过系统自带的api去获取签名很容易被伪造,不妨试试通过SVC的方式去获取(参考MT开源的方法)隐式签名校验
有一些则比较隐晦,在发现apk被修改后,会偷偷修改apk的部分功能,例如在某些多开定位软件中,会暗改ip的
经纬网等,跟实际产生一定的偏差。
PS:推荐学习芽衣大神的手撕签名校验教程
动调
注意反调试:checkfordebug
作业
np管理器注入的签名校验