首页
论坛
课程
招聘
[原创]Flutter应用逆向分析相关讨论
2021-11-19 10:18 26461

[原创]Flutter应用逆向分析相关讨论

2021-11-19 10:18
26461

前言

声明:本文只代表个人意见,发出来作抛转引玉之用。有不同观点请评论区理性讨论,也欢迎指出错误和不足。

个人的文风属于比较啰嗦的类型,因为我希望我的文章读给我奶奶听也能听得懂。

 

市面上flutter的应用数一直是在增加,而且一些恶意涉黄涉赌软件也采用了flutter技术开发。由于市面上没有合适的工具去反编译他们,导致他们的安全性真的很高。

资料搜索阅读

近日我特意去看了看最新的发布的flutter,尝试自行写了一个TestAPK,发现没法像正常的apk一样去分析。这让我没有头绪,好在有万能的谷歌让我找到了几篇非常有用的文章。

 

参考文章:

 

Reverse engineering Flutter apps (Part 1)

 

Reverse engineering Flutter apps (Part 2)

 

Introduction to Dart VM

 

虽然文章是一两年前的,但是依然是非常有意义的。

 

通过文章我们知道在发布版本的apk文件里面 libapp.so 保存的是快照,libflutter.so则是引擎,其中包括一个dart的虚拟机。

 

一个正向的生成过程:

 

flutter工程->虚拟机快照->ELF文件

 

如何要分析这个过程变得呢,需要从dartVM源码来看。

 

一个好消息是,dartVM是开源的。那我们如何通过这个源码分析整个生成过程呢。

 

除了静态读取工程相关文件,文章还提供了一种方式就是通过重编译dartVM并且使用命令自行编译libapp.so的方式来动态分析。

静态分析ELF

我们把生成的apk抽出libapp.so

 

我们直接拉到010Edit观察一番用ELF文件模板即可。

 

直接拉到dynamic_symbol这个地方

 

图片描述

 

五个函数(我擦 其他文章都只提到四个,这回谷歌怎么加到五个了)

  • _kDartVmSnapshotInstructions
  • _kDartIsolateSnapshotInstructions
  • _kDartVmSnapshotData
  • _kDartIsolateSnapshotData
  • _kDartSnapshotBuildId

两种虚拟机 两种数据快照加方法指令 还有一个新增的不知道是啥

 

不过我们可以知道

 

工程的类信息都在 kDartIsolateSnapshotData 这个里面,我们可以尝试静态的读取分析他。

读取并组装回去

一个非常不幸的消息是 发布版的快照文件里面没有能够直接调用的dart语言写的方法。这就说明不存在使用IDA直接F5或者使用fridah ook调用dart层方法测试这种情况。

 

由上面的文章知道 类 参数 常量 方法指令等信息是分开存放的。所以我们要想组装回去,就要从快照文件把他们一个一个独取出来。

 

首先最核心的也是最难的要知道每个字节代表什么意义,我找了很多资料没有直接说明出来。而且本身dartSDK在非常快速的迭代,每个版本直接的差异会导致没法按照之前的字节来解析。

 

最后还是回到了dartVM本身,我通过资料找到了一个信息。就是每个编译版本会有一个值代表dartVM的版本。

 

 

他在第20-52的位置,我们可以把它先读取出来。

 

一开始我以为这个值是那个什么github对应的commit提交的值
所以拿着这个找了半天。但是没有结果。

 

后面我直接不管他,先直接用dart --version命令得出电脑本机的dart编译版本

1
2
FlutterTest>dart --version
Dart SDK version: 2.14.4 (stable) (Wed Oct 13 11:11:32 2021 +0200) on "windows_x64"

正好是 2.14.4 版本 ,我们去 github clone 代码切换到这个分支。开始通过阅读这里面的源码来帮助我们解析这个快照文件。

dart SDK 源码阅读

源码阅读是非常枯燥的一件事,幸亏文章中指出了一些核心的类。

 

 

我们想办法从头部开始分析

 

说实话我对C++并不熟悉 导致我在看这些代码的时候非常艰难

 

好在他们的代码命名非常规范,我连蒙带猜看出了一些东西。

 

dart如何解析这个快照的头部部分代码在

 

snapsshot.h 中 这里有个非常关键的标准位

 

0xdcdcf5f5 在这里被定义为`kMagicValue

 

`

1
2
3
4
5
6
7
8
static const int32_t kMagicValue = 0xdcdcf5f5;
static const intptr_t kMagicOffset = 0;
static const intptr_t kMagicSize = sizeof(int32_t);
static const intptr_t kLengthOffset = kMagicOffset + kMagicSize; //0+32
static const intptr_t kLengthSize = sizeof(int64_t);
static const intptr_t kKindOffset = kLengthOffset + kLengthSize;//0+32+64
static const intptr_t kKindSize = sizeof(int64_t);
static const intptr_t kHeaderSize = kKindOffset + kKindSize;//0+32+64+64 = 160

分析这段代码可以得出三个东西

 

一个魔数Size

 

一个kindSize

 

而且这个kind是个枚举类 大概就是当前的编译快照类型

1
2
3
4
5
6
7
8
enum Kind {
    kFull,      // Full snapshot of an application.
    kFullCore,  // Full snapshot of core libraries. Agnostic to null safety.
    kFullJIT,   // Full + JIT code
    kFullAOT,   // Full + AOT code
    kNone,      // gen_snapshot
    kInvalid
  };

一个LengthSize

 

这个魔数也就是表示如果以这段开头的二进制就是快照的开始。

 

我们用 elftools 把这里读出来试试

1
2
3
4
5
6
7
8
snapshot_stream = BytesIO(snapshot)
                                snapshot_stream.seek(0)
                                kMagicValue = snapshot_stream.read(4).hex()
                                kLengthValue = snapshot_stream.read(8).hex()
                                kKindValue = snapshot_stream.read(8).hex()
                                print(kMagicValue)
                                print(kLengthValue)
                                print(kKindValue)

输出

1
2
3
f5f5dcdc
fed20b0000000000
0300000000000000

好像有点对得上了

 

魔数 f5f5dcdc 读出来了
03 kind 对应 AOT快照
fed20b 应该是镜像的大小

 

我们找到了头来继续往下分析

 

我找到了一个 SnapshotHeaderReader 类在clustered_snapshot.h里面

 

里面正好描写了读出来的几个头部字段

1
2
3
SnapshotHeaderReader(snapshot->kind(),
                            snapshot->Addr(),
                            snapshot->length())

接下来是两个字段一个是

 

verrsion 在 VerifyVersion()里面说明了他有128的长度

 

features 字段在 VerifyFeatures() 里面长度

 

他的长度是在

1
const char* expected_features =    Dart::FeaturesString(isolate_group, (isolate_group == NULL), kind_);

推断出来的 做了一大堆的判断拼接,不过我们可以看到最后的一个字符是 safety

 

显然是不同的版本这个长度是不同的

 

我们可以盲测 测试出这个string的长度

 

我们可以依次读出来

1
2
3
4
5
6
7
version_hash = snapshot_stream.read(32).decode('UTF-8')
 
features = snapshot_stream.read(64+64+32+11).decode('UTF-8')
 
print(version_hash)
 
print(features)

输出:

1
2
3
9cf77f4405212c45daf608e1cd646852
 
product no-code_comments no-dwarf_stack_traces_mode lazy_async_stacks no-lazy_dispatchers use_bare_instructions dedup_instructions no-"asserts" arm-eabi softfp null-safety

到这里我先暂时停下了反序列化工作,因为对于C++的不熟悉导致我非常难受。我决定先去学习一波C语言,再回头来翻译这份代码。

vsersion_hash和flutter版本的对照表

https://github.com/ptswarm/reFlutter/blob/main/enginehash.csv

 

version,Engine_commit,Snapshot_Hash
2.8.0-3.1.pre,09f1520e8b9585d133faf1eccced9357670c6d11,adf563436d12ba0d50ea5beb7f3be1bb
2.7.0-3.0.pre,bbba2b2437d739a455ecafb66a22a46d31b233ed,24d9d411c2f90c8fbe8907f99e89d4b0
2.6.0-5.2.pre,1d521d89d8d98f27be4e0ff84d5c6b72dbdc91ca,f10776149bf76be288def3c2ca73bdc1
2.5.0,f0826da7ef2d301eb8f4ead91aaf026aa2b52881,9cf77f4405212c45daf608e1cd646852
2.4.0,844c29f42a614420b2205c178f22d30b43a8b0bb,659a72e41e3276e882709901c27de33d
2.3.0,9d517f475ba1282b619477bde8e708d6a34287cf,7a5b240780941844bae88eca5dbaa7b8
2.2.0,a9d88a4d182bdae23e3a4989abfb7ea25954aad1,e4a09dbf2bb120fe4674e0576617a0dc
2.2.0-10.1.pre,d2a2e93510ad6cfc3d62a90d903b7056e4da8264,34f6eec64e9371856eaaa278ccf56538
2.1.0-12.2.pre,711ab3fda05004ee5f6035f2a0bf099fca39a129,39a9141bbcc3cae43e6f9f6b7fbaafe3
2.0.6,05e680e202af9a92461070cb2d9982acad46c83c,5b97292b25f0a715613b7a28e0734f77
1.25.0-8.3.pre,7a8f8ca02c276dce02f8dd42a44e776ac03fa9bc,9e2165577cef0f0f70f9ff072107920c
1.24.0-10.2.pre,07c1eed46b9d9b58df78566e9b8b2e42e80d3380,a2bdb58c7edf9471da9180bf8185e7f7
1.23.0-18.1.pre,1d12d82d9cb54876f58044aa52198d53ec841c3d,953aa80d78c4d8886e3e4d784fd9d95f
1.22.6,2f0af3715217a0c2ada72c717d4ed9178d68f6ed,8ee4ef7a67df9845fba331734198a953
1.21.0-9.2.pre,20a953183580250aac2e15d36007664118bda5ab,5f40b0a9f04b5018fa08a9b67fd316cd
1.20.4,d1bc06f032f9d6c148ea6b96b48261d6f545004f,04645b6182fad3d68350d84669869ce5
1.20.0-7.2.pre,60b269d898cbe0be27e9b9ba9d21eae97b887ab6,8b2ca977d1d2920b9839d1b60eade6a7
1.19.0-4.3.pre,9a28c3bcf40ce64fee61e807ee3e1395fd6bd954,59da07d9da5a83be4ce75b7913b63dbd
1.18.0-11.1.pre,ef9215ceb2884ddf520d321bcd822d1461330876,b58ead73b2c5dfec69565df469bba387
1.17.5,ee76268252c22f5c11e82a7b87423ca3982e51a7,be7d304ff826e2dfac63538e227c3cc5
1.17.1,6bc433c6b6b5b98dcf4cc11aff31cdee90849f32,74edb834fac3fcea79d7ac2d1d6f1fb2
1.17.0-dev.3.1,c9506cb8e93e5e8879152ff5c948b175abb5b997,9e7cb7c9394c24c2398410b902673e13
v1.15.17,5aff3119480996ca014ec0f8d26d74db617b5852,ee91a9191a5286c31d91a89754ba36af
v1.14.6,c4229bfbbae455ad69c967be19aee3fadd6486e1,e739779cc1d28f0f697a92f2daf5f10f
v1.13.6,bdc9708d235e582483d299642ad8682826ebb90d,81662522448cdd4d02eb060669e5d48b
v1.12.13+hotfix.9,af51afceb8886cc11e25047523c4e0c7e1f5d408,20e5c4f7dc44368ac5a17643b93665f6
v1.11.0,af04338413c3ed73316350f64248a152433073b6,2fb364d659ea53f7892be9ba5e036047
v1.10.7,9e6314d348f9b5521e3c66856324d7a9c4a928c9,c3bbfe8f226120ad0569d7b78ed2d9ef
v1.9.1+hotfix.6,b863200c37df4ed378042de11c4e9ff34e4e58c9,c8562f0ee0ebc38ba217c7955956d1cb
v1.8.3,38ac5f30a7026e870619c2e8e8c99c070d74036f,34948253b59d5a56b2ec161e17975a4e
v1.7.8+hotfix.4,fee001c93f25a1e7258e762781a7361f122d29f5,1d7acad1540192ac459cf60344efb7c1
v1.6.3,8dc3a4cde2075a4f5458fd0eb199627f5124508d,c89592e3e4956c33956c8ba0f691dbd0
v1.5.4-hotfix.2,52c7a1e849a170be4b2b2fe34142ca2c0a6fea1f,eed485c757fba5d731e4054412c99f2e
v1.4.9-hotfix.1,4737fc5cd89b8f0136e927b00f2e159444b95a73,f630ecdf457e27dd24d3b9e0a6bc1c13
v1.3.8,f4951df193a7966f9ed4da43d555eee0913d84d1,9a66dcb2da955dffdbdb0eafa0288784
v1.2.1,3757390fa4b00d2d261bfdf5182d2e87c9113ff9,0c73eb70aa4d30f450273cb424be8c62
v1.1.8,7112b72cc229e05d36716c3d7739885d3ffa72e6,317d4c7e607b1fd7d682c0010aadf1d0
v1.0.0,7375a0f414bde4bc941e623482221db2fc8c4ab5,8343f188ada07642f47c56e518f1307c


 

未完待续


【看雪培训】《Adroid高级研修班》2022年夏季班招生中!

最后于 2021-11-25 10:56 被小黄鸭爱学习编辑 ,原因: 新增一部分内容
收藏
点赞2
打赏
分享
最新回复 (12)
雪    币: 25
活跃值: 活跃值 (588)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
amwpecel 活跃值 2021-11-19 11:49
2
0
暂停一下,开下晨会
雪    币: 2365
活跃值: 活跃值 (1579)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
TUGOhost 活跃值 2021-11-19 16:24
3
0
晨会开完能续上吗
雪    币: 1066
活跃值: 活跃值 (2078)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小黄鸭爱学习 活跃值 2021-11-19 17:30
4
0
TUGOhost 晨会开完能续上吗
来了来了
雪    币: 11069
活跃值: 活跃值 (951)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xJJuno 活跃值 2021-11-21 14:37
5
0
追更...
雪    币: 510
活跃值: 活跃值 (443)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hzzheyang 活跃值 2021-11-22 09:33
6
0
晨会开完了吗
雪    币: 55
活跃值: 活跃值 (636)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
New对象处 活跃值 2021-11-22 09:44
7
0
大佬已经开始研究Flutter了
雪    币: 0
活跃值: 活跃值 (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
aiwans 活跃值 2021-11-23 16:43
8
0

1111

最后于 2021-11-23 17:16 被aiwans编辑 ,原因:
雪    币: 276
活跃值: 活跃值 (442)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hpphpp 活跃值 2021-11-24 21:47
9
0
支持大佬
雪    币: 11598
活跃值: 活跃值 (2942)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
LowRebSwrd 活跃值 4 2021-11-25 20:08
10
0
支持 
雪    币: 22
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
万里星河 活跃值 2021-11-27 20:24
11
0
支持一下 虽然我看不懂 哈哈
雪    币: 217
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_oowzftna 活跃值 6天前
12
0
大佬请问一下dart版本前后有什么特征吗,我看了个so找不到他的veraion
雪    币: 1066
活跃值: 活跃值 (2078)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
0
mb_oowzftna 大佬请问一下dart版本前后有什么特征吗,我看了个so找不到他的veraion
就是前面的hash值,当然因为dart引擎是开源的。开发者可以重新编译这个dartvm,去掉这个hash值头部标志位。所以你说的找不到version绝对是有可能的。
游客
登录 | 注册 方可回帖
返回