声明

本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】联系作者立即删除!

逆向目标

  • 设备:Google Pixel4,Android 10,已 root
  • APP:UnCrackable-Level1.apk(可在公众号回复 APP 获取)
  • APP 检测了 root,如果手机 root 了,会强制退出 APP,过了 root 检测后,还需要输入一个字符串进行校验。

安装 ADB

adb(Android Debug Bridge)即安卓调试桥,安装后可以在电脑上与手机进行交互,Android Studio 等工具里面会自带 adb,有时候我们并不想下载这么大的工具,所以这里介绍一下 Android SDK Platform-Tools,它是 Android SDK 的一个组件,它包括与 Android 平台交互的工具,主要是 adb 和 fastboot,官方下载地址:https://developer.android.com/studio/releases/platform-tools ,下载完成后将该目录添加到环境变量,USB 连接手机,手机上设置允许 USB 调试,使用命令 adb version 可查看版本信息,adb devices 可以查看当前连接的设备,如下图所示:

安装 Frida

Frida 是一款基于 Python + JavaScript 的 Hook 与调试框架,首先电脑端使用命令 pip install frida-tools 安装 frida 模块(此命令默认会安装最新版的 frida 和 frida-tools,如),然后下载 frida-server,下载地址:https://github.com/frida/frida/releases

frida-server 要根据你电脑端安装的 frida 版本和手机的 CPU 架构来选择对应的,使用命令 frida --version 可以查看 frida 版本,使用命令 adb shell 进入手机,输入 getprop ro.product.cpu.abi 查看 CPU 架构,如下图所示,我这里 frida 是 15.2.2 版本,手机 CPU 为 arm64,所以我下载的是 frida-server-15.2.2-android-arm64.xz

某些 Android 低版本使用高版本 frida 可能有问题,遇到问题可尝试降低 frida 版本来解决。

将下载好的 frida-server 使用 adb push 命令传到手机的 /data/local/tmp/ 目录下,并给予 777 读、写、执行的权限,然后直接运行 frida-server,正常不会有任何输出,当然也可以使用 & 等方式让其在后台运行。

然后另开一个 cmd 使用命令 frida-ps -U 可查看手机进程,有输出则正常。

逆向分析

使用 adb install 命令安装 UnCrackable-Level1.apk,打开该 APP,会检测到 root,出现 Root detected! 的提示,如下图所示:

使用 JEB、JADX、GDA 等工具反编译 apk,直接搜索关键字 Root detected! 即可定位到检测的地方:

可以看到图中有三个检测方法 c.a()c.b()c.c(),其中一个返回为真,则弹出 Root detected!,然后前面还有一个 onClick 方法,如果点击 OK 按钮,则触发 System.exit(0);,即退出 APP,先点进三个检测方法看看:

a() 方法通过检测 Android 系统环境变量中是否有 su 文件来判断是否被 root;

b() 方法通过检测 Build.TAGS 中是否包含字符串 test-keys 来判断是否被 root;

c() 方法通过检测指定路径下是否包含指定的文件来判断是否被 root。

所以我们这里就有多种过掉检测的方法:

方法一:Hook 三个检测方法,让它们都返回 false,不再执行后续的 a 方法,就不会退出 APP 了:

  1. Java.perform(
  2. function(){
  3. console.log("[*] Hook begin")
  4. var vantagePoint = Java.use("sg.vantagepoint.a.c")
  5. vantagePoint.a.implementation = function(){
  6. console.log("[*] Hook vantagepoint.a.c.a")
  7. this.a();
  8. return false;
  9. }
  10. vantagePoint.b.implementation = function(){
  11. console.log("[*] Hook vantagepoint.a.c.b")
  12. this.b();
  13. return false;
  14. }
  15. vantagePoint.c.implementation = function(){
  16. console.log("[*] Hook vantagepoint.a.c.c")
  17. this.c();
  18. return false;
  19. }
  20. }
  21. )

方法二:Hook a() 方法,置空,什么都不做,不弹出对话框,也不退出 APP:

  1. Java.perform(
  2. function(){
  3. console.log("[*] Hook begin")
  4. var mainActivity = Java.use("sg.vantagepoint.uncrackable1.MainActivity");
  5. mainActivity.a.implementation = function(){
  6. console.log("[*] Hook mainActivity.a")
  7. }
  8. }
  9. )

方法三:Hook onClick() 方法,点击 OK 后不让其退出 APP,注意这里是内部类的 Hook 写法:

  1. Java.perform(
  2. function(){
  3. console.log("[*] Hook begin")
  4. var mainActivity$1 = Java.use("sg.vantagepoint.uncrackable1.MainActivity$1");
  5. mainActivity$1.onClick.implementation = function(){
  6. console.log("[*] Hook mainActivity$1.onClick")
  7. }
  8. }
  9. )

方法四:Hook System.exit() 方法,点击 OK 后不让其退出 APP:

  1. Java.perform(
  2. function(){
  3. console.log("[*] Hook begin")
  4. var javaSystem = Java.use("java.lang.System");
  5. javaSystem.exit.implementation = function(){
  6. console.log("[*] Hook system.exit")
  7. }
  8. }
  9. )

root 检测过掉之后,APP 还要输入一个字符串,输入错误会提示 That's not it. Try again.,如下图所示:

分析 Java 代码,有一个 if-else 判断,obj 为输入的字符串,a.a(obj) 判断为真,就表示输入正确。

跟到 a.a() 方法,可以看到 bArr 是内置的字符串,通过 equals() 方法比较输入的 str 是否和 bArr 相等:

bArr 的值,主要经过 sg.vantagepoint.a.a.a() 方法处理后得到,继续跟进去可以发现是 AES 加密算法:

这里就可以直接 Hook sg.vantagepoint.a.a.a(),直接拿到加密后的值,也就是我们要的正确字符串,由于这里返回的是 ASCII 码,所以我们还需要在 JavaScript 代码中使用 String.fromCharCode() 将其转换成正常字符,Hook 代码如下:

  1. Java.perform(
  2. function(){
  3. var cryptoAES = Java.use("sg.vantagepoint.a.a");
  4. cryptoAES.a.implementation = function(bArr, bArr2){
  5. console.log("[*] Hook cryptoAES")
  6. var secret = "";
  7. var decryptValue = this.a(bArr, bArr2);
  8. console.log("[*] DecryptValue:", decryptValue)
  9. for (var i=0; i < decryptValue.length; i++){
  10. secret += String.fromCharCode(decryptValue[i]);
  11. }
  12. console.log("[*] Secret:", secret)
  13. return decryptValue;
  14. }
  15. }
  16. )

运行 Hook 脚本有两种方式,一是结合 Python 使用,二是直接通过 frida 命令使用脚本,注入 Hook 代码也有个时机问题,有时候需要在 APP 启动就开始 Hook,有时候可以等 APP 启动加载完毕了再 Hook,本例中,过 root 检测的时候,如果采用第一、二种方法,即 Hook 三个检测方法或者 a 方法,那就需要在 APP 启动的时候就 Hook,如果采用第三、四种方法,即 Hook onClick() 或者 System.exit() 方法,那么等 APP 启动了再 Hook 也可以。

结合 Python 使用

首先来看一下结合 Python 怎么使用,JavaScript 代码如下(frida-hook.js):

  1. /* ==================================
  2. # @Time : 2022-08-29
  3. # @Author : 微信公众号:K哥爬虫
  4. # @FileName: frida-hook.js
  5. # @Software: PyCharm
  6. # ================================== */
  7. Java.perform(
  8. function(){
  9. console.log("[*] Hook begin")
  10. // 方法一:Hook 三个检测方法,让它们都返回 false,不再执行后续的 a 方法,就不会退出 APP 了
  11. // var vantagePoint = Java.use("sg.vantagepoint.a.c")
  12. // vantagePoint.a.implementation = function(){
  13. // console.log("[*] Hook vantagepoint.a.c.a")
  14. // this.a();
  15. // return false;
  16. // }
  17. // vantagePoint.b.implementation = function(){
  18. // console.log("[*] Hook vantagepoint.a.c.b")
  19. // this.b();
  20. // return false;
  21. // }
  22. // vantagePoint.c.implementation = function(){
  23. // console.log("[*] Hook vantagepoint.a.c.c")
  24. // this.c();
  25. // return false;
  26. // }
  27. // 方法二:Hook a() 方法,置空,什么都不做,不弹出对话框,也不退出 APP
  28. // var mainActivity = Java.use("sg.vantagepoint.uncrackable1.MainActivity");
  29. // mainActivity.a.implementation = function(){
  30. // console.log("[*] Hook mainActivity.a")
  31. // }
  32. // 方法三:Hook onClick() 方法,点击 OK 后不让其退出 APP
  33. // var mainActivity$1 = Java.use("sg.vantagepoint.uncrackable1.MainActivity$1");
  34. // mainActivity$1.onClick.implementation = function(){
  35. // console.log("[*] Hook mainActivity$1.onClick")
  36. // }
  37. // 方法四:Hook System.exit 方法,点击 OK 后不让其退出 APP
  38. var javaSystem = Java.use("java.lang.System");
  39. javaSystem.exit.implementation = function(){
  40. console.log("[*] Hook system.exit")
  41. }
  42. var cryptoAES = Java.use("sg.vantagepoint.a.a");
  43. cryptoAES.a.implementation = function(bArr, bArr2){
  44. console.log("[*] Hook cryptoAES")
  45. var secret = "";
  46. var decryptValue = this.a(bArr, bArr2);
  47. console.log("[*] DecryptValue:", decryptValue)
  48. for (var i=0; i < decryptValue.length; i++){
  49. secret += String.fromCharCode(decryptValue[i]);
  50. }
  51. console.log("[*] Secret:", secret)
  52. return decryptValue;
  53. }
  54. }
  55. )

Python 代码如下(frida-hook.py):

  1. # ==================================
  2. # --*-- coding: utf-8 --*--
  3. # @Time : 2022-08-29
  4. # @Author : 微信公众号:K哥爬虫
  5. # @FileName: frida-hook.py
  6. # @Software: PyCharm
  7. # ==================================
  8. import sys
  9. import frida
  10. def on_message(message, data):
  11. if message['type'] == 'send':
  12. print("[*] {0}".format(message['payload']))
  13. else:
  14. print(message)
  15. with open("./frida-hook.js", "r", encoding="utf-8") as fp:
  16. hook_string = fp.read()
  17. # 方式一:attach 模式,已经启动的 APP
  18. process = frida.get_usb_device(-1).attach("Uncrackable1")
  19. script = process.create_script(hook_string)
  20. script.on("message", on_message)
  21. script.load()
  22. sys.stdin.read()
  23. # 方式二,spawn 模式,重启 APP
  24. # device = frida.get_usb_device(-1)
  25. # pid = device.spawn(["owasp.mstg.uncrackable1"])
  26. # process = device.attach(pid)
  27. # script = process.create_script(hook_string)
  28. # script.on("message", on_message)
  29. # script.load()
  30. # device.resume(pid)
  31. # sys.stdin.read()

Python 代码中,attach 模式 Hook 已经存在的进程,spawn 模式会重启 APP,启动一个新的进程并挂起,在启动的同时注入 frida 代码,适用于在进程启动前的一些 Hook,attach 模式传入的是 APP 名称,spawn 模式传入的是 APP 包名,查看 APP 名称和包名的方法有很多,这里介绍两个 frida 命令,frida-ps -Uai:列出安装的程序,frida-ps -Ua:列出正在运行中的程序,如下图所示,本例中 Uncrackable1 就是 APP 名称,owasp.mstg.uncrackable1 就是包名:

运行 Python 代码,注意手机端也要启动 frida-server,过掉 root 检测后,先随便输入字符串,点击 VERIFY 就会 Hook 到正确的字符串为 I want to believe,再次输入正确的字符串,即可验证成功。

frida 命令

不使用 Python,也可以直接使用 frida 命令来实现,和前面 Python 一样也有两种模式,同样的一个是 APP 名一个是包名:

frida -U Uncrackable1 -l .\frida-hook.js:attach 模式,APP 启动后注入 frida 代码;

frida -U -f owasp.mstg.uncrackable1 -l .\frida-hook.js --no-pause:spawn 模式,重启 APP,启动的同时注入 frida 代码。

至此,我们完美绕过了 root 检测,并成功找到了正确的字符串。

【APP 逆向百例】Frida 初体验,root 检测与加密字符串定位的更多相关文章

  1. [转帖]APP逆向神器之Frida【Android初级篇】

    APP逆向神器之Frida[Android初级篇] https://juejin.im/post/5d25a543e51d455d6d5358ab 说到逆向APP,很多人首先想到的都是反编译,但是单看 ...

  2. Hybird App ( 混合模式移动应用)开发初体验

    最近1,2个月一直都尝试开发一款Hybird app,遇到了很多问题,谈谈自己的体会. Hybird app (混合模式移动应用),它利用例如安卓端webview组件+HTML5内嵌的方式混合的方式开 ...

  3. Net Core平台灵活简单的日志记录框架NLog+Mysql组合初体验

    Net Core平台灵活简单的日志记录框架NLog初体验 前几天分享的"[Net Core集成Exceptionless分布式日志功能以及全局异常过滤][https://www.cnblog ...

  4. 【Spark深入学习 -15】Spark Streaming前奏-Kafka初体验

    ----本节内容------- 1.Kafka基础概念 1.1 出世背景 1.2 基本原理 1.2.1.前置知识 1.2.2.架构和原理 1.2.3.基本概念 1.2.4.kafka特点 2.Kafk ...

  5. 【腾讯Bugly干货分享】基于 Webpack & Vue & Vue-Router 的 SPA 初体验

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d13a57132ff21c38110186 导语 最近这几年的前端圈子,由于 ...

  6. 【尝新】微信小程序初体验

    文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/?t=1474644089434 根据文档地址中下载微信开发工具后,按照文档指引可以创建一个快速体验的小d ...

  7. python--爬虫入门(七)urllib库初体验以及中文编码问题的探讨

    python系列均基于python3.4环境 ---------@_@? --------------------------------------------------------------- ...

  8. Flume 实战(1) -- 初体验

    前言: Flume-ng是数据收集/聚合/传输的组件, Flume-ng抛弃了Flume OG原本繁重的zookeeper和Master, Collector, 其整体的架构更加的简洁和明了. 其基础 ...

  9. 基于 Webpack & Vue & Vue-Router 的 SPA 初体验

    基于 Webpack & Vue & Vue-Router 的 SPA 初体验 本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com ...

  10. vue.js2.0 自定义组件初体验

    理解 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能.在有些情况 ...

随机推荐

  1. css过去及未来展望—分析css演进及排版布局的考量

    读初二的时候,学校有了计算机,也简单地介绍了下网页,不过那是的html 都是table,也没有去细看.到了高中,qq空间有个html模式,为了让文章好看点.也浅尝辄止地学了下css css简介 在HT ...

  2. Log4Shell 漏洞披露已近一年,它对我们还有影响吗?

    在 Log4Shell 高危漏洞事件披露几乎整整一年之后,新的数据显示,对全球大多数组织来说,补救工作是一个漫长.缓慢.痛苦的过程. 根据漏洞扫描领先者 Tenable 公司的遥测数据来看,截至今年1 ...

  3. A/B 实验避坑指南:为什么不建议开 AABB 实验

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 本文将针对日常开设 A/B 实验过程中一个不太合理的使用方法--AABB 实验进行详细的解释,告诉大家为什么不建议 ...

  4. C++11实用特性1

    1 原始字面量 有时候在输出一个路径字符串时,编译器会将其中的部分内容识别成转义字符进行输出,可以用R "xxx(原始字符串)xxx"其中()两边的字符串可以省略.原始字面量R可以 ...

  5. 基于C++11特性的线程池

    写在前面:本文学习自基于C++11实现线程池,代码部分均属于该博主,自己只是想记录以下自己的认知,并以这种方式加深一下自己对于多线程的理解 1 前置知识 RAII管理机制 简单来说RAII机制是一种对 ...

  6. OpenShift 与 OpenStack:让云变得更简单

    OpenShift 与 OpenStack 都是在 2010.2011 年左右创建的,用于构建可扩展云平台的开源技术,两者都用于在混合云环境中构建可扩展系统.从历史来看,OpenStack 的存在时间 ...

  7. POJ 2484博弈——对称法

    题目链接:http://poj.org/problem?id=2484 题意:Alice和Bob玩游戏,从一堆圆环形排列的硬币中拿硬币,每次可以拿一个或者两个,但必须拿连续的(两个中间有空位也视为不连 ...

  8. 【网络爬虫学习】第一个Python爬虫程序 & 编码与解码详解 & Pythonの实现

    本节编写一个最简单的爬虫程序,作为学习 Python 爬虫前的开胃小菜. 下面使用 Python 内置的 urllib 库获取网页的 html 信息.注意,urllib 库属于 Python 的标准库 ...

  9. AcWing 第 13 场周赛  补题记录

    比赛链接:Here AcWing 3811. 排列 签到题, 先输出 \(n\) 然后输出 \(1\sim n -1\) 即可 AcWing 3812. 机器人走迷宫 不会什么特别高级的方法 qaq, ...

  10. Intellij IDEA安装与配置教程(Windows版)

    Intellij IDEA(简称IDEA)是Java语言的集成开发环境,在业界公认为是一款优秀的Java开发工具.分为Community社区版(免费)和Untimate终极版(付费). IDEA是一款 ...