参考了许多大佬的博客,在此特别诚挚感谢oacia大佬和其他大佬的博客和指导!

1.flutter和apk基础结构介绍

首先下载附件,是一个apk文件,用jadx打开

可以看见flutter字样,而flutter是一种目前比较流行的android框架,很多app都是用的该框架构建,而该原生框架是建立在app的native层

Android的系统架构采用了分层架构的思想。从下往上依次分为Linux内核、硬件抽象层(HAL)、系统Native库和Android运行时环境、Java框架层以及应用层这5层架构,其中每一层都包含大量的子模块或子系统

而平时我们接触到的都是应用层和Java框架层,包括用Jadx对apk进行逆向时也只是在逆向Java层的逻辑。如果想要逆向native层,就需要对android进行解包

apk本身是一个包,压缩了运行时的依赖、配置文件以及native库,也就是.so,将apk文件后缀名修改成.zip后,即可解压查看这些文件

也可以使用androidkiller这个工具对apk进行分析、修改

最基础的app配置文件放在AndroidManifest.xml,这个文件里面存放的有app的很多配置,如该题的配置情况如下,可以在这个文件里面看到该应用的包名,名称、SDK的版本等等信息,这些信息在app取证里面很有用,对之后的动态调试SO层也有很大帮助。

<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:compileSdkVersion="33" android:compileSdkVersionCodename="13" package="com.example.flutter_application_1" platformBuildVersionCode="33" platformBuildVersionName="13">
<application android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:icon="@mipmap/ic_launcher" android:label="flutter_application_1" android:name="android.app.Application">
<activity android:configChanges="density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:exported="true" android:hardwareAccelerated="true" android:launchMode="singleTop" android:name="com.example.flutter_application_1.MainActivity" android:theme="@style/LaunchTheme" android:windowSoftInputMode="adjustResize">
<meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data android:name="flutterEmbedding" android:value="2"/>
<uses-library android:name="androidx.window.extensions" android:required="false"/>
<uses-library android:name="androidx.window.sidecar" android:required="false"/>
</application>
</manifest>

至于其他的文件夹,大家可以自行查阅,这里就不一一说明。

而native层的.so文件就放在lib的几个文件夹里面

这三个文件夹分别代表了不同架构的.so文件。我们如果想用真机调试.so文件,那么就要用真机对应的架构,不能乱用。

2.blutter安装以及使用

接下来把lib文件进行解包,因为flutter使用的是dart语言,并且采用了dartVM的方法进行拍摄快照,所以我们现在要使用一些工具对.so文件进行快照解析,市面上对flutter的逆向工具都是这个原理。

但是有一个问题,dart快照是可以更改的,随着DartSdk版本的更新,reflutter和flutter逆向助手已经停止更新,这次的这个题flutterSDK过高,两个工具都无法破解,于是找到了blutter这个工具

官方地址:

GitHub - worawit/blutter: Flutter Mobile Application Reverse Engineering Tool

用git把blutter.py拉进kali里面(如果拉不进就直接到GitHub上下zip解压就行),然后安装依赖。

sudo apt install python3-pyelftools python3-requests git cmake ninja-build

build-essential pkg-config libicu-dev libcapstone-dev

若报错如下

说明你该更新你的apt源

sudo apt-get update

下载完成情况如图

接下来就可以用这个工具了,将解压后的app放进虚拟机,在blutter目录下运行.py文件,注意有两个参数,前一个参数是.so文件所在的其中一个目录,后一个参数是结果输出目录

若成功会解析稍微长一点的时间,耐心等待即可,如果有下图结果即为解析完成

完成后在输出目录会有五个文件和文件夹

按照作者的说法,分别对应的是

pp.txt:在对象池里面的所有dart对象(dart采用了对象池的设计模式),这里面可以查看很多对象池变量的偏移地址



objs.txt:对象池中对象的完整(嵌套)转储,在这里我理解成对象池里面的方法和相应的偏移量

blutter_frida.js:这个是用于对该flutter程序hook的js代码,应用在frida这个工具里面(接下来会讲到)

ida_script:这个文件夹装的是.so文件的符号表还原脚本,因为dart语言是依靠偏移量识别函数的,所以也能依靠偏移量还原函数

asm:对dart语言的反编译结果,里面有很多dart源代码的对应偏移

3.动态调试flutter程序

接下来就是利用frida工具hook插桩以及动态调试破解该程序了

环境:具有python环境的win10系统、kali系统

设备:pixel3(需要root)

重点:必须是欧版,如果不是欧版OEM无法打开,不可能刷的了机

具体root过程参考https://sspai.com/post/76276

工具:adb调试桥、IDA7.7工具

3.1.下载adb

https://blog.csdn.net/x2584179909/article/details/108319973

3.2.运行IDA

注意,在此之前需要将chall.apk修改成可调试状态

具体方法为利用androidkiller打开程序->在AndroidManifest.xml里面第二行插入

android:debuggable="true"

如果程序SDK版本比较老,这样就可以,但是这个程序的targetSdkVersion是33,是高版本,签名会出问题,所以在apktool.xml改成27或者28即可

两处改好后就可以进行编译,得到新的程序。

完成后即可安装到手机上

adb install chall_killer.apk

查看自己的手机是什么架构可以用下列代码

adb shell getprop ro.product.cpu.abi

在ida的下图文件夹内找到android_server64(我的真机架构是arm64位的)

连接手机(手机上打开USB调试),打开终端,利用adb程序在手机上下载chall.apk,安装完成后把之前找到的server文件push到手机里执行

adb push android_server64 /data/local/tmp/as

adb shell

su #加载手机root权限

cd /data/local/tmp/

chmod 777 as #给server文件可读可写可执行权限

./as -p 12345 #用12345端口运行server

如果运行成功会有一个正在监听的提示,说明这个命令端已经成为了server端监听了

接下来重新开启一个命令行,adb转发端口

adb forward tcp:12345 tcp:12345

保持收发端口一致后启动ida,将libapp.so放进ida

用刚才blutter解析得到的addName.py还原符号表

得到了符号表之后,查看解析的asm里面的main.dart,查找主程序里面的函数

在flutter官网查找四个函数的含义均为dart的API

表单交互 (Forms)

或者可以在这篇博客上找到

Flutter基建 - 按钮全解析 - 掘金

onChanged():这个API在删除或插入文本的时候的回调函数

onSubmitted():当用户完成文本输入并按下键盘上的“完成”按钮时的回调函数

onLongPressed():在屏幕上保持了一段时间

onTap():用户点击事件完成(点击提交按钮时)

现在查看我们的程序,可以看见这个程序的窗口组成,而最重要的应该是提交按钮,对应的也就是onTap()回调函数所做的

所以直接过滤器查找这个函数(也可以直接用之前在main.dart里面找到的函数地址)



回调函数在0xE03C4处

之后我们查看程序发现有256这个变量

再加上这里很明显的RC4加密流程

可以大概得知这是一个RC4加密。

3.3.frida工具hook key值

接下来需要用到frida工具,frida是一款基于python + java 的hook框架,可运行在android、ios、linux、win、osx等各平台,主要使用动态二进制插桩技术

安装部分可以看这里

frida安装正确流程

上面步骤中用blutter解析快照时,工具自动帮我们写了一个插桩脚本,叫做blutter_frida.js,只需要在下图所示部分修改成上面有RC4加密的函数地址,即可hook出密文

改完之后使用frida加载这个js脚本

frida -U -f com.example.flutter_application_1 -l blutter_frida.js

随便输入点什么执行程序即可hook得到密文

3.4.动态调试部分

现在可以调试一下我们的apk应用程序

首先打开应用debug模式,如果上面的androidkiller如果不行,可以用面具开,具体流程如下图

adb shell

su

magisk resetprop ro.secure 0

magisk resetprop ro.debuggable 1

getprop ro.debuggable #如果回显为1则已经开启

stop

start #上面两步重启手机

这个时候下载monitor(DDMS)用于观察程序进程是否开启(如果是真机可能不需要这一步)

打开monitor.bat,可以看见设备上的进程

这个时候挂起程序

jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8639

运行结果如下图

如果有报错 致命错误:无法附加到目标 VM。

那可能是端口搞错了,这里要填写的是应用程序的端口,而不是adb运行server的端口。

运行成功的话monitor里面程序那行进程栏会显示为绿色

接下来进行调试,调试设置如下图

设置完成点击Attach to process...进行附加程序调试,附加我们的程序即可

现在先找密钥,而密钥是RC4加密的异或操作下的变量,我们把断点下在异或的指令上

f9断到这个地方之后可以看见X2变量是有赋值的,我们利用trace跟踪该变量,并将值都打印出来

import idc
print(idc.ger_reg_value('X2'),',',end='')

此处点击运行直接跳过,跳过后发现手机上能够输入了,这个时候输入字符(字符个数可以往前看用frida工具hook出来的key数量)然后点√

感谢oacia师傅的提示,如果不点√就f9不会有输入,程序会一直卡在第一个异或的密钥上

上图是第一个异或的密钥,但是如果检查下来发现密文和这个密钥异或之后得不到输入,重新检查一下会发现还要异或一个0xff即可

addr = [14, 14, 68, 80, 29, 201, 241, 46, 197, 208, 123, 79, 187, 55, 234, 104, 40, 117, 133, 12, 67, 137, 91, 31, 136,
177, 64, 234, 24, 27, 26, 214, 122, 217]
key = [184,
132,
137,
215,
146,
65,
86,
157,
123,
100,
179,
131,
112,
170,
97,
210,
163,
179,
17,
171,
245,
30,
194,
144,
37,
41,
235,
121,
146,
210,
174,
92,
204,
22
]
flag = ""
for i in range(len(addr)):
flag += chr(addr[i] ^ 0xff ^ key[i]) print(flag)

4.本文知识点来源

[原创]flutter逆向 ACTF native app-Android安全-看雪-安全社区|安全招聘|kanxue.com

认识 Flutter 是什么?

403 Forbidden

一日一技|如何 root 一台 Pixel 手机 - 少数派

windows下载安装adb(极其简单)-CSDN博客

frida安装正确流程

Flutter基建 - 按钮全解析 - 掘金

表单交互 (Forms)

ACTF flutter逆向学习的更多相关文章

  1. 逆向学习XXclient怎样仅仅执行一个实例

    个人觉得学习分两种, 一种是当面请教和直接从书本网络中的资料学习. 其二就是看着令你惊叹的作品-顿悟. 什么?顿悟不了?那我们就一起来逆向学习吧!差点忘了,我并不打算提供Demo,这并不重要,难道你打 ...

  2. Anroid逆向学习从编写so到静动态调试分析arm的一次总结

    Anroid逆向学习从编写so到静动态调试分析arm的一次总结 一.前言 最近跟着教我兄弟学逆向这篇教程学习Android逆向,在第七课后作业反复折腾了好几天,正好在折腾的时候对前面的学习总结一波,动 ...

  3. 爱了!阿里大神最佳总结“Flutter进阶学习笔记”,理论与实战

    前言 "小步快跑.快速迭代"的开发大环境下,"一套代码.多端运行"是很多开发团队的梦想,美团也一样.他们做了很多跨平台开发框架的尝试:React Native. ...

  4. android逆向学习小结--CrackMe_1

    断断续续的总算的把android开发和逆向的这两本书看完了,虽然没有java,和android开发的基础,但总体感觉起来还是比较能接收的,毕竟都是触类旁通的.当然要深入的话还需要对这门语言的细节特性和 ...

  5. Android逆向学习资料

    Android逆向基础之Dalvik虚拟机: https://lyxw.github.io/archivers/Android%E9%80%86%E5%90%91%E5%9F%BA%E7%A1%80% ...

  6. JS面向对象逆向学习法,让难理解的统统一边去(1)~

    对于面向对象我只能说呵呵了,为什么呢,因为没对象--- 既然你看到了这里,说明你有一定的基础,虽然本系列文章并不会过多的讲述基础部分,请做好心理准备. 本篇比较简单,这篇文章的意义是让你明白学习面向对 ...

  7. Flutter 案例学习之:GridView

    GitHub:https://github.com/happy-python/flutter_demos/tree/master/gridview_demo 在 ListView 中,如果将屏幕的方向 ...

  8. 逆向学习-DLL注入

    DLL注入技术,可以实现钩取API,改进程序,修复Bug. DLL注入指的是向运行中的其他进程强制插入特定的DLL文件. DLL注入命令进程自行调用LoadLibrary()API,加载用户指定的DL ...

  9. <逆向学习第三天>手动脱FSG壳,修复IAT。

    其实对于简单的壳来说,脱壳常用的方法也无非是那几种,但是每种有每种的好处,具体使用那种方法视情况而定,我今天学习的这个壳很简单,但是重点在于修复IAT. 一.查壳: FSG 2.0的壳. 二.脱壳: ...

  10. <逆向学习第二天>如何手动脱UPX、Aspack壳

    UPS.AsPack压缩壳介绍: UPX .AsPack是一款先进的可执行程序文件压缩器.压缩过的可执行文件体积缩小50%-70% ,这样减少了磁盘占用空间.网络上传下载的时间和其它分布以及存储费用. ...

随机推荐

  1. 小知识:Docker环境缺少vi命令,如何解决

    docker exec可以使用--user参数指定root用户,进入安装vi即可: [opc@oci-001 ~]$ docker exec -it --user root testdb bash b ...

  2. MySQL高级12-事务原理

    一.事务概念 事务是一组操作的集合,他是一个不可分割的工作单位,事务会把所有操作作为一个整体一起向系统提交或者撤销请求操作,即这些操作要么同时成功,要么同时失败. 二.事务特性 原子性(Atomici ...

  3. CAP项目集成带身份和证书验证的MongoDB

    大家好,我是Edison. 最近,在使用CAP事件总线时,碰到了这样一个需求:微服务采用的是MongoDB,而且还是带身份验证 和 SSL根证书验证的.由于目前网上能找到的资料,都是不带身份验证的Mo ...

  4. 日常Bug排查-读从库没有原子性?

    日常Bug排查系列都是一些简单Bug排查.问题虽小,但经常遇到,了解这些问题,会让我们少走点弯路,提升效率.说不定有些问题你遇到过哦:) Bug现场 业务开发同学突然问了笔者一个问题,从库读会不会没有 ...

  5. c语言代码练习14

    //设计一个猜数字游戏,需要提示猜大了还是小了,直到猜对为止 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include & ...

  6. Python操作Word水印:添加文字或图片水印

    在Word文档中,可以添加半透明的图形或文字作为水印,以保护文档的原创性,防止未经授权的复制或使用.除了提供安全功能外,水印还可以展示文档创作者的信息.附加的文档信息,或者仅用于文档的装饰.本文将介绍 ...

  7. 基于Electron27+Vite4+React18搭建桌面端项目|electron多开窗口实践

    前段时间有分享一篇electron25+vite4搭建跨桌面端vue3应用实践.今天带来最新捣鼓的electron27+react18创建跨端程序.electron多开窗体(模拟QQ登录窗口切换主窗口 ...

  8. JS深入之内存详解,数据结构,存储方式

    理解了本文,就知道深拷贝和浅拷贝的底层,了解赋值的底层原理. 可以结合另一篇文章一起食用:深拷贝与浅拷贝的区别,实现深拷贝的方法介绍. 以下是正文: 栈数据结构 栈的结构就是后进先出(LIFO),如果 ...

  9. 【源码解读(二)】EFCORE源码解读之查询都做了什么以及如何自定义批量插入

    引言 书接上回,[源码解读(一)]EFCORE源码解读之创建DBContext查询拦截,在上一篇文章中,主要讲了DBContext的构造函数,以及如何缓存查询方法提升查询性能,还有最重要的拦截查询,托 ...

  10. Wampserver搭建DVWA和sqli-labs问题总结

    Wampserver 搭建 DVWA 和 sqli-labs 问题总结 遇到问题解决的思路方法 百度,博客去搜索相关的问题,人工智能 chatgpt 查看官方文档,查看注释. 本次解决方法就是在文档的 ...