Android逆向学习(六)绕过app签名校验,通过frida,io重定向(上)

news2024/12/23 13:18:07

Android逆向学习(六)绕过app签名校验,通过frida,io重定向(上)

一、写在前面

这是吾爱破解正己大大教程的第五个作业,然后我的系统还是ubuntu,建议先看一下上一个博客,关于动态调试的,因为我这才发现动态调试是真的有很大用处,然后我们开始今天的教程(拖更很久了,最近真的很忙事情好多,抽空出一期博客,这一节博客问题其实挺多的,如果有不对的地方请指出,不胜感激)

二、任务目标

  1. 破解签名,使程序可以正常运行

三、实现方法

1. 破解签名防止闪退

我们先简单看一下这个反编译之后的java文件

20231004205012

这里有个check,以及system终结的一个代码

解决方法具体有两种,一种简单的方法就是直接更改函数的返回值,让他只返回true

我们分析一下checkSign的代码

20231004205325

最主要就是修改这个地方,把false改成true

我们发现areEqual调用后有一个分支,就说明改变这个分支就可以了

20231004205711

我们直接修改smali代码后就是这样的

20231004211445

然后我们就可以看到这个页面是什么样子的了

20231004211546

然后还有一种方式就是我们动态调试一下,然后我们直接改变这个hash值

20231004211853

就是这个hash值,这个就是这个软件原来的hash,因为我们对这个软件进行了很多修改,所以现在的hash和原来的hash已经不一样了,所以我们需要改成和现在一样

我们直接在areEqual上面这里打一个断点,然后开始一步一步往下走,就可以看到这样:

20231004213430

这很明显就是要进行比较的两个值,然后我们把这个修改一下就可以了

20231004213554

然后我们打包运行一下(上一个方法的 add-int/lit8 v1, v1, 0x1 代码已经去除了 )

发现是可以进行运行的

20231004213918

2.关于剩余的签名

然后我这里一直有一些bug就是我点击验证总是会出问题,就是程序直接卡死,讲道理不应该这样才对,然后我直接debug动态调试发现是so校验的时候会卡死,讲道理不应该呀,我用真机测试也会出现这种情况,通过JEB进行动态调试之后发现就是在loadLibrary的时候会出现这个问题

搞了好久都不知道怎么回事,就只能把这个签名校验直接干掉了(字面意义上的干掉)

20231005160820

就是这三行直接全部消灭掉,当然这样一般肯定是有问题的,so文件里面一般都会有一些可能其他进程需要的函数,所以我建议最好不要用这个方法,我是实在没办法了才这样,要是不这样我可能连着好几天都没法更新新的blog,所以请大家见谅

但是不管如何我都会遇到这个问题,难不成因为版本问题?算了不管了先这样。

20240108204430

后来我想了想,不如反编译so文件看看,说不定可以看到哪里有问题,然后我们反编译后是这样

20240108211748

突然间想到,说不定是因为我把名称改成了东北往事,然后load的时候名称对不上

重新把东北往事换成了wuaipojie,结果还是完蛋,点击验证还是闪退,看来跟这个没关系,问题只有天知道了,就删掉继续吧,这样我们需要面对的就是API签名校验,CRC校验和hash校验

3.新API校验

我们同样进行一个逆向,直接看源代码

private final boolean useNewAPICheck() {
        String str;
        Signature[] signatureArr;
        try {
            if (Build.VERSION.SDK_INT >= 28) {
                signatureArr = getPackageManager().getPackageInfo(getPackageName(), 134217728).signingInfo.getApkContentsSigners();
            } else {
                signatureArr = getPackageManager().getPackageInfo(getPackageName(), 64).signatures;
            }
            str = MD5Utils.INSTANCE.MD5(Base64Utils.INSTANCE.encodeToString(signatureArr[0].toByteArray()));
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            str = "";
        }
        Log.e("zj2595", "newsign:" + str);
        return Intrinsics.areEqual("074f64af5821ae6aa1ac1779ad5687ad", str);
    }

这个就是新API校验的函数,当然按照正己大大的教程,我们是可以得到这个Log.e中的这个信息,那我们就先按照正己大大的教程,查看一下这个log就行了,我采用的方法是直接用adb看

首先打开终端,adb连接后打开shell,然后使用logcat关键词查询,就可以看到这个

20240108220253

这个然后复制过去,替换掉就可以了,就像这样

20240108220314

但是这就有一个问题了,一半正常情况下是不会有人专门log出来,所以这个方法在实战中是没有用处的,所以一般来说,我们的操作有

  1. 动态调试找到这个str
  2. 直接强行修改返回值,永远返回一个true

这两招是比较实用的

20240108220447

4.CRC校验(有问题,请先看完再实际操作)

这个方法也差不多,首先看一下crc校验的代码

    public final boolean check_crc(long j) {
        try {
            ZipEntry entry = new ZipFile(getPackageCodePath()).getEntry("classes.dex");
            Log.e("zj2595", "dexCrc:" + entry.getCrc());
            return entry.getCrc() == j;
        } catch (Exception e) {
            e.printStackTrace();
            return true;
        }
    }

关于这个j我也看到了,我把相关代码摘出来

我们可以看到相关的代码有一个j

textView5.setText(challengeFifth.check_crc(j) ? "通过" : "不通过");

然后我们找到这个函数的参数
(TextView textView, ChallengeFifth challengeFifth, TextView textView2, TextView textView3, TextView textView4, TextView textView5, long j, TextView textView6, TextView textView7, View view)

顺藤摸瓜往上找,找到了

long parseLong = Long.parseLong(getString(2131755055));

button.setOnClickListener(new ChallengeFifth$.ExternalSyntheticLambda0(textView, this, textView2, textView3, textView6, textView4, parseLong, textView5, textView7));

这时候就比较难办了,修改也不好修改(强行修改返回值我不讲了,这个方法算作弊了,我们就学习一种新的破解方法)

原教程io重定向写的有点简略了,然后这个其实用frida可以很方便,我们在后面会详细讲到frida,这里我觉得我们就直接写,先对frida有个了解。

frida的安装我在之前的博客写过了,就是camodroid和tracedroid那篇,这里我们就直接使用,根据代码分析是getPackageCodePath()获得的地址,我们查看一下这个代码

20240109120111

这个是在android.content.ContextWrapper下面,之后我们就hook一下试一试

import sys
import frida

def on_message(messages, data):
    if messages["type"] == "send":
        print("[+] {}".format(messages["payload"]))
        print("[+] {}".format(messages))
    else:
        for name in messages:
            print("[+] {}".format(messages[name]))

process = frida.get_usb_device().attach('东北往事')
with open("frida.js") as f:
    script = process.create_script(f.read())
    # 这是将frida 的脚本给读取进来了
script.on("message", on_message)
script.load()
sys.stdin.read()

下面是frida的js脚本

Java.perform(function () {
    Java.use("android.content.ContextWrapper").getPackageCodePath.implementation=function () {
        var result = this.getPackageCodePath();
        send(result);
        return result;
    }
})

我们运行的结果是

‘/data/app/~~VEf27Hz4Vx9zDMiZ-UPXZQ==/com.zj.wuaipojie-Qpx1v_KIH3iiBblSp6vvtg==/base.apk’

这就是运行的路径了

所以我们目前的思路就是更改这个获取路径方法的返回值,将它定位到其他地方,我们当然可以直接hook check_crc的函数,但是这样还是一种作弊的方式吧,因为我写这个博客不是为了完成52的作业,而是学习更多的技术,如果是hook check_crc方法的话用下面这个脚本。

Java.perform(function () {
    Java.use("com.zj.wuaipojie.ui.ChallengeFifth").check_crc.overload('long').implementation = function (j) {
        var result = this.check_crc(j);
        send(result);
        return true;
    }
})

如果按我们之前的思路,那就开始更改路径

我们的方法就是,将这个返回值,给修改成我们放入原始包的地址,这样它检测的地址就是我们没有修改的包,说干就干.

我们还是首先把这个的apk包,用adb工具给发送到手机上

adb push 52demo.apk /data/local/tmp
cp /data/local/tmp/base.apk /data/user/0/com.zj.wuaipojie/files/

然后我们修改返回值为这个地址加apk文件名

Java.perform(function () {
    Java.use("android.content.ContextWrapper").getPackageCodePath.implementation=function () {
        var result = this.getPackageCodePath();
        send(result);
        var javaString = Java.use("java.lang.String")
        var newstring = javaString.$new("/data/user/0/com.zj.wuaipojie/files/base.apk")
        send(newstring)
        return newstring;
    }
})

然后扯淡的地方来了,这个始终不会出现crc校验通过,我不知道为什么会这样,按照道理来说应该是没问题的才对啊,这个就直接跳过了,不过这个思路是完全没有问题的,我感觉可能是因为版本对不上导致的,所以我直接hook crc函数算了,如果大家知道这个问题的话请联系我(可能是因为我用的第13节课的课件?最多只到7关的那个,可能是这个原因,等以后我换换试试)

这个就先这样过了吧

20240109214318

三、结尾

20240109214942

还是虎哥镇楼,作为我csdn博客的封面

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1372747.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿赵UE学习笔记——8、贴图导入设置

阿赵UE学习笔记目录 大家好,我是阿赵。   继续学习虚幻引擎的用法,这次来说一下贴图的导入设置。   在内容浏览器里面可以看到纹理类型的资源,就是贴图了,鼠标悬浮在上面可以看到这个纹理贴图的信息: 双击纹理贴图…

使用Scikit Learn 进行识别手写数字

使用Scikit Learn 进行识别手写数字 作者:i阿极 作者简介:数据分析领域优质创作者、多项比赛获奖者:博主个人首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞👍收藏&#x1f…

虽迟但到!MySQL 可以用 JavaScript 写存储过程了!

任何能用 JavaScript 来干的事情,最终都会用 JavaScript 来干 背景 不久前,Oracle 在 MySQL 官方博客官宣了在 MySQL 中支持用 JavaScript 来写存储过程。 最流行的编程语言 最流行的数据库。程序员不做选择,当然是全都要。 使用方法 用 J…

压测必经之路,Jmeter分布式压测教程

01、分布式压测原理 Jemter分布式压测是选择其中一台作为调度机(master),其他机器作为执行机(slave);当然一台机器也可以既做调度机,也做执行机。 调度机执行脚本的时候,master将会…

软件测试工具Robot Framework如何安装

安装文件准备 表1 安装文件准备 Robot框架结构 为了更好的了解环境安装,我们先看下框架结构: 图1 Robot Framework Architecture Robot Framework 通过导入不同的库,就可以使用库中所提供的关键字,从而时行相关的测试。有几个标…

掌握Java Future模式及其灵活应用

第1章:引言 大家好,我是小黑,今天咱们来聊聊Future。咱们程序员在日常工作中,肯定都遇到过需要处理耗时任务的情况,特别是在Java领域。比如说,小黑要从网络上下载数据,或者要执行一个计算密集型…

MySql -数据库基本概念

一、数据库的基本概念 1.为什么要学数据库? 之前我们如果想将一些数据实现永久化存储,可以怎么做呢?没错。使用IO流的技术将数据保存到本地文件中但是接下来我有这样一个需求:将下面的user.txt文件中的王五年龄修改为35 张三 2…

Java顺序表(1)

🐵本篇文章将对顺序表中的方法进行模拟实现 一、线性表 线性表是指在逻辑结构上呈连续的线性结构,而在物理结构上不一定是连续的结构,常见的线性表有:顺序表、链表、栈、队列等 二、顺序表 顺序表一般采用数组来存储数据&#x…

C++——map和set的基本使用

目录 一,关联式容器 二,键值对 三,set的使用 3.1 set介绍 3.2 set的插入和删除 3.3 set的pair 3.4 multiset 四,map的使用 4.1 map介绍 4.2 map实现简易字典 4.3 map实现统计次数 4.4 map的[] 五,使用map或…

CHS_01.2.1.1+2.1.3+进程的概念、组成、特征

CHS_01.2.1.12.1.3进程的概念、组成、特征 进程进程的概念 进程的组成——PCB进程的组成——PCB进程的组成——程序段、数据段知识滚雪球:程序是如何运行的?进程的组成进程的特征 知识回顾与重要考点 从这个小节开始 我们会正式进入第二章处理机管理相关…

暴雨信息发布算力网络应用平台打造零感知算网服务新模式

为进一步优化算力网络应用服务能力和降低算力网络使用难度,暴雨信息突破基于算力网络的实例跨域协同与迁移、基于测试评估的应用度量和解构等技术,研发并推出算力网络应用平台。该系统通过提供一种即开即用、按需付费的零感知算网应用服务,使…

捕捉小红书开年顶流,品牌快“跟风”上车!

2024年开年,“南方小土豆”纷纷北上,元旦期间哈尔滨收入近60亿元,“冰雪”一跃成为今冬最炙手可热的流行趋势! 千瓜数据显示,小红书“冰雪”相关商业笔记同比去年增长649.84%。本期,千瓜将从“冰雪”场景出…

离散数学-二元关系

4.1关系的概念 1)序偶及n元有序组 由两个个体x和y&#xff0c;按照一定顺序排序成的、有序数组称为有序偶或有序对、二元有序组&#xff0c; 记作<x&#xff0c;y>&#xff0c;其中x是第一分量&#xff0c;y是第二分量。 相等有序偶&#xff1a;第一分量和第二分量分…

Excel·VBA按指定顺序排序函数

与之前写过的《ExcelVBA数组冒泡排序函数》不同&#xff0c;不是按照数值大小的升序/降序对数组进行排序&#xff0c;而是按照指定数组的顺序&#xff0c;对另一个数组进行排序 以下代码调用了《ExcelVBA数组冒泡排序函数》bubble_sort_arr函数&#xff08;如需使用代码需复制…

EasyPOI导出报表

报表导出是一种很常见的功能&#xff0c;只要是开发都会涉及到这一功能&#xff0c;早些年经常集成poi完成导出功能&#xff0c;我之前也有写过关于poi导出的文章&#xff0c;现如今&#xff0c;也有了更为方便的导出插件 — EasyPOI&#xff0c;废话不多说&#xff0c;开始撸代…

内网渗透实战攻略

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 介绍 什么是内网&#xff1f; 什么是内网渗透&#xff1f; 内网渗透的目的&#xff1a; 内网…

el-table实现多行合并的效果,并可编辑单元格

背景 数据为数组包对象&#xff0c;对象里面有属性值是数组&#xff1b;无需处理数据&#xff0c;直接使用el-table包el-table的方法&#xff0c;通过修改el-table的样式直接实现多行合并的效果 html代码 <template><div><el-table size"mini" :d…

Python基础知识:整理9 文件的相关操作

1 文件的打开 # open() 函数打开文件 # open(name, mode, encoding) """name: 文件名&#xff08;可以包含文件所在的具体路径&#xff09;mode: 文件打开模式encoding: 可选参数&#xff0c;表示读取文件的编码格式 """ 2 文件的读取 文…

设计模式-规格模式

设计模式专栏 模式介绍模式特点应用场景规格模式和策略模式的区别和联系代码示例Java实现规格模式Python实现规格模式 规格模式在spring中的应用 模式介绍 规格模式&#xff08;Specification Pattern&#xff09;是一种行为设计模式&#xff0c;其目的是将业务规则封装成可重…

【笔记】书生·浦语大模型实战营——第三课(基于 InternLM 和 LangChain 搭建你的知识库)

【参考&#xff1a;tutorial/langchain at main InternLM/tutorial】 【参考&#xff1a;(3)基于 InternLM 和 LangChain 搭建你的知识库_哔哩哔哩_bilibili-【OpenMMLab】】 笔记 基础作业 这里需要等好几分钟才行 bug&#xff1a; 碰到pandas相关报错就卸载重装 输出文字…