一次金融APP的解密历程

news2025/7/12 7:42:21

声明:本文仅限于技术讨论与分享,严禁用于非法途径。若读者因此作出任何危害网络安全行为后果自负,与本号及原作者无关。

前言:

客户仅提供官网下载地址给我们测试。但是由于官网的版本不是最新的,APP会强制你升级。而升级后的APP,是进行加固后的,无法使用frida进行hook,注入进程。那同样也无法使用SSL Unpinning进行限制客户端校验证书。新版app使用查壳软件显示未加壳,但是查看源代码明显少了很多代码,且很多都是变量声明而已。

绕过更新:

我们要想能对APP渗透测试,一般都是需要抓包和解密的。首先使用burp进行抓包代理,官网版本的APP(以下统称旧版APP),是可以轻松抓到APP的包的(该条请求为检验APP最新版本的请求)。但是内容使用了加密,具体什么加密是不得而知。

img

获取到请求密文:

vVAK0jos5eT9gmQJaHOaYbqZ1mgXoBH3bee3MTF3G5wNRHRoPPOYokZLT4MQqaPDN%2BLeEYpIzzDJeErDHcDfhY8muosLfOaw35W3BuCxDNtuNFB86RumMBtOcQXT08qw

响应包未json,urldecode后为:

{"duration":"0ms","note":"","code":1,"resultDES":"UX/jHk6yqix2yxZIrf0rSIuOjCy6oGxjCPUfBL2avG+DWy/++NW16+YQHVFQ+Nj2w9VOWGcH4OxFtGxbR6K7I6pY0Q9hkP9gc0K0JLZ5O+PwOW72nzissCiLG+cHqadKHzkPOQDdBUuBoa4W1Jz7fQ=="}

通过desStr和resultDES,一开始我猜测他为des加密,具体是不是,后续再说。

先进入APP,但是一进入APP就提示更新:

img

通过前言,我们知道是不能更新的。(当然不乏某些技术大佬也可以把新版APP搞定,我技术有限,感觉旧版的比较容易搞)。那我们就明确了目标,要先绕过更新校验。

**对于不了解hook和frida的同学,我这边推荐先去网上了解下,还有安装之类的,再来看此篇文章。

【----帮助网安学习,以下所有学习资料免费领!加weix:yj009991,备注“ csdn ”获取!】
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC漏洞分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)

首先我们明确一下思路,要怎么绕过这个更新校验呢?

(1)直接反编译,修改APP的版本信息为99.99之类的;

(2)通过修改版本验证请求,使用http层面去绕过;

(3)使用hook,去重写更新函数,或者绕过更新函数;

第一点要app能支持反编译且不存在校验签名。第二点要能知道加密密文的密钥。所以我选择第三种:

通过jadx搜索更新,发现了两处,成功获取到源代码。

img

类名分别为:com.xxxx.AppUpdate和com.xxxx.WelcomeActivity,通过代码审计可以看到,是先调用的WelcomeActivity,WelcomeActivity再去调用的AppUpdate:

img

跟踪进入AppUpdate,调用的checkNativeAppVersion():

img

通过上述代码,我们可以看到,这边就是用于判断是否升级的函数。

public void onResponse(Call call, Response response) throws IOException {
    try {
        JSONObject jSONObject = new JSONObject(C.s2(new JSONObject(URLDecoder.decode(response.body().string(), DataUtil.UTF8)).getString("resultDES"), Config.WHITE_KEY, Config.IV.getBytes()));
        if (jSONObject.optInt("code", -1) > 0) {
            JSONObject optJSONObject = jSONObject.optJSONObject("object");
            if (optJSONObject == null) {
                return;
            }
            if (WakedResultReceiver.CONTEXT_KEY.equals(optJSONObject.optString("isUpdate", ChatConfig.CARD_TYPE))) {
                nativeAppVersionInterface.updateApp(optJSONObject.optString("desc", "当前有新版本,是否需要更新"), optJSONObject.optString(ClientCookie.VERSION_ATTR, ""));
            } else {
                nativeAppVersionInterface.noUpdateApp();
            }
        } else {
            nativeAppVersionInterface.showError(jSONObject.optString("note"));
        }
    } catch (JSONException e) {
        e.printStackTrace();
        nativeAppVersionInterface.showError(e.getMessage());
    }
}

当JSONObject.optInt(“code”, -1) > 0时,是会去进行升级的,否则则执行nativeAppVersionInterface.noUpdateApp()。

这边分析完后,其实我们就可以写js进行hook操作了。

我们的hook思路可以这样设置了:

重写checkNativeAppVersion函数,执行执行nativeAppVersionInterface.noUpdateApp()。

Ps:因为我一开始直接重写了checkNativeAppVersion,只执行了console.log(“enter checkNativeAppVersion”),没有对APP进行启动,这样就会直接卡死在启动页。

附上js代码:

if(Java.available){
    console.log('success');
        Java.perform(function(){
        var appUpdate = Java.use("com.xxxx.AppUpdate");
        appUpdate.checkNativeAppVersion.implementation = function(a,b,c,d,e,f){
            console.log("enter AppUpdate");//判断是否进入该hook函数,进入会执行该命令
            f.noUpdateApp();//直接执行不需要更新函数,APP会自动进入
        }
        });
}

使用命令:frida -U -l .\xxx.js -f 包名 --no-pause

img

成功进入:

img

解密:

已经成功进入该APP,但是如果想成功进行渗透测试的话,还需要能解开APP的加密。通过des字段,初步判断为des加密,再回头看看刚刚更新的那个请求,是有用c.s2()函数进行操作的,大概率s2就是解密函数。

JSONObject jSONObject = new JSONObject(C.s2(new JSONObject(URLDecoder.decode(response.body().string(), DataUtil.UTF8)).getString("resultDES"), Config.WHITE_KEY, Config.IV.getBytes()));

可以看到s2的三个参数,即前面响应包中的json字段里面的resultDES参数,然后其次是Config.WHITE_KEY, Config.IV两个参数,其中Config.IV是以字节数组的形式进行传参的。通过跳转可以看到配置文件的参数。

img

然后呢,因为获取到密钥和偏移量iv,这样的话des就可以解了。但是问题是解不开。后续的思路就是如果可以直接hook这两个加解密函数的话,是不是就可以不用管他的加解密了。

img

s1和s2函数不在java层,那我们就需要hook native层的代码。Hook so文件。首先我们先把安装包后缀apk改成zip,然后解压。就可以找到wkb-1.2.2.so的文件了。(路径为lib/arm64-v8a/wkb-1.2.2.so,前面的arm64根据自己测试机的CPU架构进行选择。)直接用ida打开,在导出函数里面搜索des:

img

里面有很多des的相关函数。可使用以下js进行hook导出函数:

if(Java.available){
    console.log('success');
        Java.perform(function(){
        var point = Module.findExportByName("libwkb-1.2.2.so","desDecryptByteArray");
        Interceptor.attach(point,{
            onEnter: function(args){
                console.log("Hook start");
                console.log("args[0]=" + args[0]); //打印我们java层第一个传入的参数
                console.log("args[1]=" + args[1]); //打印我们java层传入的第二个参数
            },
            onLeave: function(retval){ //onLeave: function(retval)是该函数执行结束要执行的代码,其中retval参数即是返回值
                console.log("return:" + retval); //打印返回值
            }
        });
        });
}

但是这边很奇怪的是,通过函数findExportByName找到的地址都是为null,一开始以为是还没加载到so文件,但是后续进入APP后还是一样为null。(有知道的大佬可以说下)

img

这就比较蛋疼了,得手动计算地址。首先先获取so文件的地址,看能不能获取到,若不行,则表示未加载so文件。

var soAddr = Module.findBaseAddress("libwkb-1.2.2.so");
console.log("soAddr:" + soAddr);

img

有地址出来,说明so文件是存在的,可以正常调用。那么这边就要去计算函数偏移量。之前在网上看到别人的一个公式:

**函数地址=so****初始地址+**函数偏移量+1

但是我后面尝试了好几个,好像不同手机不同的计算方法,也可能我操作的有问题。我这边的函数地址就是:

**函数地址=so****初始地址+**函数偏移量

不用加一。我自己是用这个方法测试计算的:找到一个导出函数可以被查询到的,比如我这边使用的就是JNI_OnLoad函数:

img

img

获取JNI_OnLoad的地址为0x79d5d7883c,然后使用这个地址减去so的地址:

0x79d5d7883c − 0x79d5d67000 = 1183c

差值刚好为JNI_OnLoad的偏移量,所以我这边就不用再进行加一操作了。

这样我们就可以成功hook任意函数了。通过我一个个尝试发现,以下函数一个都没调用过:

img

然后呢,我查找了s2函数的用例,发现被decodeSm4的函数调用过。

img

我就尝试了一下,hook了sm4EncryptByteArr:

img

img

附上js:

var soAddr = Module.findBaseAddress("libwkb-1.2.2.so");
var point = soAddr.add(0x136f0);
Interceptor.attach(point,{
            onEnter: function(args){
                console.log("Hook start");
                console.log("args[0]=" + args[0]); //打印我们java层第一个传入的参数
                console.log("args[2]=" + Java.vm.getEnv().getStringUtfChars(args[2], null).readCString()); //打印我们java层传入的第三个参数
                console.log("args[3]=" + Java.vm.getEnv().getStringUtfChars(args[3], null).readCString()); //打印我们java层传入的第四个参数
            },
            onLeave: function(retval){ //onLeave: function(retval)是该函数执行结束要执行的代码,其中retval参数即是返回值
                console.log("return:" + Java.vm.getEnv().getStringUtfChars(retval, null).readCString()); //打印返回值
                // retval.replace(0); //替换返回值为0
                // return retval;
            }
        });

Ps:通过ida里面的参数,我们可以看到第二个参数为类,我们就没给他打印出来。

我人傻了,一开始的des字眼和偏移量这些都符合des的加密方式,误导了我好久,一直往des方向去找。

尾声:

其实很早我就已经解密成功了,直接通过java层,刚刚发现调用s2的decodeSm4函数,直接hook那边即可成功获取请求和响应的明文:

img

但是若通过js去操作修改数值,实在太麻烦了,要获取密钥和加密方式,通过脚本自动去加解密,所以我才会去hook native层,获取到密钥。因为上述密钥Config.WHITE_KEY,其实是还有一层加密的,通过hook decodeWhiteKey函数的返回值,成功获取了密钥。

img

img

其实后续我也尝试去修改版本号绕过,但是事实证明,代码存在验签:

09fb86b8fbc058e8ecab0e5a8a04be6

可以看到,把版本号修改为99.9.99,成功绕过了更新检测,但是他还存在一个盗版验签检测:

5db5880584da7a62dea2030e6c00a57

验签代码一样需要用hook去绕过。所以前面说的方法一也是行不通的。然后我又突发奇想,有没有可能他密文里面就包含版本信息,那如果我使用99.9.99的版本,抓取密文,然后再安装旧版APP,在他去请求版本更新时,替换密文,是不是可以绕过呢?经过尝试,结果是:可以。他的版本校验就是在服务端,这种方法也可以绕过。

总结:

不用轻易相信别人留下的信息,还是得根据自己的分析得出结论。其实后续我一直在想为什么那个字段是des呢,感觉之前是des加密,后续金融行业都进行了国密改造,然后字段并未更改,导致这种现象,当然只是猜测。至此,已完成对这APP的抓包和加解密。

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

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

相关文章

搭建lamp平台

apache安装步骤 检查是否已经rpm安装httpd服务,已安装则卸载服务。 [rootlocalhost ~]# rpm -e rpm -qa | grep httpd --nodeps 开发工具安装 如果编译安装无法执行,可能是开发工具没有安装,执行下面命令即可安装。(如已安装则跳…

【springboot进阶】优雅使用 MapStruct 进行类复制

项目中经常会遇到这样的一个情况:从数据库读取到数据,并不是直接返回给前端做展示的,还需要字段的加工,例如记录的时间戳是不需要的、一些敏感数据更是不能等等。传统的做法就是创建一个新的类,然后写一堆的get/set方法…

数据结构【队列】

文章目录(一)队列定义(二)队列实现(1)创建结构体(2)具体函数实现及解析1.1 初始化队列1.2入队列1.3出队列1.4取队首元素1.5取队尾元素1.6返回队列个数1.7判断是否为空1.8销毁队列&am…

springCloud的 consul的下载与安装

下载地址:Install | Consul | HashiCorp Developer 下载自己需要使用的版本 下载后会有一个exe 文件通过cmd 命令行来执行这个exe 文件consul agent -dev -client0.0.0.0 出现此页面后执行8500 端口 请求地址:http://127.0.0.1:8500/ 出现此页面说明启…

黑苹果入门:必备工具篇

以下给大家汇总的这些软件工具都是我们在安装使用黑苹果过程中可能会用到的,至于使用方法,在这里我就不做过多介绍了。 本次只提供软件下载地址,不提供使用方法,不知道如何使用软件工具的童鞋,可以在百度翻翻相关教程…

第5章 C语言高级的库函数

文章目录文档配套视频讲解链接地址第05章 C库函数5.1 assert.h 断言库5.2 ctype.h 测试和映射字符5.3 math.h 数学库5.4 stdlib.h 标准库1. 字符串转整数、浮点数2. strtod 把字符串中的数字转换成浮点数并返回数字的下一个字符的位置3. strtol 字符串转整数4. strtoul 字符串转…

vue3 antd多级动态菜单(二)后台管理系统(两种方法过滤有无子菜单children)

vue3 antd 多级动态菜单(精修版本) 两种方法实现对children的筛选相关文章推送(供参考)场景复现实现效果解决方法hasChildren与noChilren函数过滤v-if v-else判断有无children【推荐】🔥两种方法公用代码sunmmary下期预…

ESP32 入门笔记06: WIFI时钟 + FreeRTOS+《两只老虎》 (ESP32 for Arduino IDE)

ESP32FreeRTOS Esp32 模块中已经提供了 FreeRTOS(实时操作系统)固件。 FreeRTOS有助于提高系统性能和管理模块的资源。FreeRTOS允许用户处理多项任务,如测量传感器读数,发出网络请求,控制电机速度等,所有…

靶向肿瘤代谢,助力攻克癌症

肿瘤代谢的简介 肿瘤代谢的起源在于奥托沃伯格 (Otto Warburg) 的假设,他也因发现线粒体呼吸链复合物 IV 而获得 1931 年诺贝尔生理学或医学奖。Warburg 观察到,与正常组织相比,体外癌组织切片使用大量葡萄糖生成乳酸 (即使在有氧的情况下也是…

SBT10100VDC-ASEMI低压降贴片肖特基二极管SBT10100VDC

编辑-Z SBT10100VDC在TO-263封装里采用的2个芯片,其尺寸都是62MIL,是一款低压降贴片肖特基二极管。SBT10100VDC的浪涌电流Ifsm为150A,漏电流(Ir)为4uA,其工作时耐温度范围为-65~150摄氏度。SBT10100VDC采用金属硅芯片材质&#x…

QScintilla代码跳转时indicator工作不正确的问题

首先看我这几个文章,知道一下indicator是什么,以及上下文: https://biao2488890051.blog.csdn.net/article/details/126798996?spm1001.2014.3001.5502 目标: 我现在要做按住 ctrl 鼠标左键点击释放 发生函数/变量的 定义/声明…

Pandas中你一定要掌握的时间序列相关高级功能

💡 作者:韩信子ShowMeAI 📘 数据分析实战系列:https://www.showmeai.tech/tutorials/40 📘 本文地址:https://www.showmeai.tech/article-detail/389 📢 声明:版权所有,转…

ceph浅谈

总谈 ceph简介 用上ceph,多台机器的磁盘空间在一起了,在一台机器上就可以看到使用所有空间。 还可以保存多份安全备份 存储先ceph,自我管理修复,跨机房,节点越多,并行化,论上,节点越…

【虚幻引擎UE】UE5 实现相机录制视频并导出(C++调用外部exe)

说明: 该功能暂不支持导出声音。 由于OpenCV3和UE5不太兼容,因此考虑制作外部exe实现视频合成。 一、创建渲染目标 二、创建Actor加场景捕获组件2D 三、创建UE5内的C++代码 1、实现 SavePicToFile 导出图片蓝图函数 .cpp文件 // Fill out your copyright notice in the De…

数字集成电路设计(二、Verilog HDL基础知识)

文章目录1. 语言要素1.1 空白符1.2 注释符1.3 标识符1.3.1 转义标识符1.4 关键字1.5 数值1.5.1 整数及其表示方式1.5.2 实数及其表示方式1.5.3 字符串及其表示方式2. 数据类型2.1 物理数据类型2.1.1 连线型2.1.2 寄存器型2.2 连线型和寄存器型数据类型的声明2.2.1 连线型数据类…

深入了解海豚调度DolphinScheduler

深入了解海豚调度DolphinScheduler一、海豚调度介绍二、海豚调度特性三、建议配置四、名词解释五、模块介绍六、功能介绍1.项目首页2.工作流定义3.工作流实例4.任务实例5.任务定义七、任务类型1.SQL2.SPARK节点3.Apache Zeppelin八、集群部署1.前置准备工作2.准备 DolphinSched…

实现注册与登录模块

目录 1、加载依赖 2、实现jwt工具类jwtUtil类 3、实现config.filter.JwtAuthenticationTokenFilter类 4、配置config.SecurityConfig类 5、创建后端api之前对数据库进行修改 6、写API一共需要的三个地方 7、实现三个接口 8、验证用户登录用API调试 9、https://jwt.io/解…

MySQL表的增删查改(CRUD)

文章目录前言一、新增数据二、查询数据全列查询指定列查询表达式查询指定别名查询去重查询排序查询条件查询分页查询三、修改数据四、删除数据前言 CRUD代表: 增加(create) ,查询(retrieve) ,更新(update) ,删除(delete) 单词首字母。 一、新增数据 SQL使用insert关键字来表…

二叉搜索树、红黑树详解、红黑树高的应用、TreeMap的应用(图文详解)-Kotlin版本代码

二叉搜索树 何为二叉搜索树? 二叉搜索树是一种特殊的二叉树,它的左子节点总是小于或等于根节点,而右子节点 总是大于或等于根节点。 如下图,即是一颗二叉搜索树。 对于二叉搜索树来说,中序遍历可以遍历按照节点值…

【JavaSE】重载和重写

前言: 作者简介:爱吃大白菜1132 人生格言:纸上得来终觉浅,绝知此事要躬行 如果文章知识点有错误的地方不吝赐教,和大家一起学习,一起进步! 如果觉得博主文章还不错的话,希望三连支持&#xff01…