逆向工程Flutter应用程序Part 1

第1章:掉进兔子洞

首先,我将介绍Flutter堆栈的一些背景知识及其工作原理。

您可能已经知道:Flutter是从头开始构建的,具有自己的渲染管道和小部件库,从而使其真正跨平台,并具有一致的设计,无论在什么设备上运行都可以感觉到。

与大多数平台不同,flutter框架的所有基本渲染组件(包括动画,布局和绘画)都在中完全向您公开package:flutter

您可以从Wiki / The-Engine-architecture的官方架构图中看到这些组件

从逆向工程的角度来看,最有趣的部分是Dart层,因为这是所有应用程序逻辑所在的位置。

但是Dart层是什么样的?

Flutter将Dart编译为本机汇编代码,并使用尚未公开深入记录的格式,更不用说完全反编译和重新编译了。

为了进行比较,其他平台(例如React Native)仅捆绑了缩小的javascript,这很容易检查和修改,此外,Android上Java的字节码已被详细记录,并且有许多免费的反编译器。

尽管没有混淆(默认情况下)或加密,但是Flutter应用程序目前仍然非常难以逆向工程,因为它需要深入了解Dart内部知识才能刮擦表面。

从知识产权的角度来看,这使得Flutter变得非常出色,几乎可以防止窥探代码。

接下来,我将向您展示Flutter应用程序的构建过程,并详细说明如何对它产生的代码进行反向工程

快照

Dart SDK具有高度的通用性,您可以在许多不同的平台上以许多不同的配置嵌入Dart代码。

运行Dart的最简单方法是使用dart可执行文件,该可执行文件像脚本语言一样直接读取dart源文件。它包括我们称为前端的主要组件(解析Dart代码),运行时(提供运行代码的环境)以及JIT编译器。

您还可以dart用来创建和执行快照,这是Dart的预编译形式,通常用于加快常用的命令行工具(如pub)的速度。

ping@debian:~/Desktop$ time dart hello.dart
Hello, World!

real    0m0.656s
user    0m0.920s
sys     0m0.084s

ping@debian:~/Desktop$ dart --snapshot=hello.snapshot hello.dart
ping@debian:~/Desktop$ time dart hello.snapshot
Hello, World!

real    0m0.105s
user    0m0.208s
sys     0m0.016s

如图所见,使用快照时,启动时间大大缩短。

默认的快照格式是kernel,相当于AST的Dart代码的中间表示形式。

在调试模式下运行Flutter应用时,Flutter工具会创建内核快照,并使用调试运行时+ JIT在您的android应用中运行该快照。这使您能够通过热重载在运行时调试应用程序并实时修改代码。

对于我们来说不幸的是,由于对RCE的关注日益增加,在移动行业中,使用您自己的JIT编译器已不受欢迎。iOS实际上阻止您完全执行像这样的动态生成的代码。

但是,还有两种类型的快照,app-jitapp-aot,它们包含编译后的机器代码,它们可以比内核快照更快地初始化,但它们不是跨平台的。

快照的最终类型app-aot,仅包含机器代码,不包含内核。这些快照是使用中提供的gen_snapshots工具生成的flutter/bin/cache/artifacts/engine/<arch>/<target>/,稍后再介绍。

但是,它们不仅仅是Dart代码的编译版本,实际上,它们是在调用main之前VM堆的完整“快照”。这是Dart的一项独特功能,也是与其他运行时相比,其初始化速度如此之快的原因之一。

Flutter将这些AOT快照用于发行版本,您可以在使用以下内容构建的Android APK的文件树中看到包含它们的文件flutter build apk

ping@debian:~/Desktop/app/lib$ tree .
.
├── arm64-v8a
│   ├── libapp.so
│   └── libflutter.so
└── armeabi-v7a
    ├── libapp.so
    └── libflutter.so

在这里,您可以看到两个libapp.so文件,它们是作为ELF二进制文件的a64和a32快照。

gen_snapshots这里输出ELF /共享对象的事实可能会引起误解,它不会将dart方法公开为可以在外部调用的符号。而是,这些文件是“群集快照”格式的容器,但在单独的可执行部分中包含编译的代码,以下是它们的结构:

ping@debian:~/Desktop/app/lib/arm64-v8a$ aarch64-linux-gnu-objdump -T libapp.so

libapp.so:     file format elf64-littleaarch64

DYNAMIC SYMBOL TABLE:
0000000000001000 g    DF .text  0000000000004ba0 _kDartVmSnapshotInstructions
0000000000006000 g    DF .text  00000000002d0de0 _kDartIsolateSnapshotInstructions
00000000002d7000 g    DO .rodata        0000000000007f10 _kDartVmSnapshotData
00000000002df000 g    DO .rodata        000000000021ad10 _kDartIsolateSnapshotData

AOT快照采用共享对象形式而不是常规快照文件的原因是因为gen_snapshot在应用启动时需要将生成的机器代码加载到可执行内存中,而最好的方法是通过ELF文件。

有了这个共享.text库,链接器将把该节中的所有内容加载到可执行内存中,从而允许Dart运行时随时调用它。

您可能已经注意到有两个快照:VM快照和Isolate快照。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值