Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

admin 2023年10月23日22:30:43评论50 views字数 7976阅读26分35秒阅读模式

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

最近发现Flutter和Rust的讨论也都变得多了起来,然后就像了下,他们两个能否结合一下呢,于是便有了今天这一篇可以水的文章了。

环境准备

因为我们需要结合Flutter和Rust,因此,这两个基础环境的准备是必要的,下面列出一下我用到的版本,其实也就是最新版本。

  • Flutter 3.13.7
  • Cargo 1.73.0 (9c4383fb5 2023-08-26)

然后,这里我们直接采用了flutter_rust_bridge这一个库,在使用这个库之前呢,需要做一些前期的准备,也就是提前安装一些依赖,具体细节可以参考下官方文档,根据自己需要的平台自行添加相关依赖。

搭建过程

首先,肯定是新建一个Flutter项目,这个过程就不过多描述了,因为这篇文章也不是一个教大家写Flutter应用的文章,相信能看这篇文章的,应该也会自己构建项目了。

依赖添加

在新建完成项目之后,我们需要添加一些依赖,具体如下:

dependencies:
  # ... other ...
  ffi: ^2.1.0
  flutter_rust_bridge: ^1.82.3

dev_dependencies:
  # ... other ...
  ffigen: ">=8.0.0 <9.0.0"

新建Rust项目

这里,我们直接使用JetBrains公司给开发的最新的Rust的IDE,咱就是用最新的,这不是给IDE打广告蛤,大家也可以根据自己的喜好来。注意,这里需要选择Library,不要选Application,不过选了也不要紧,删一下文件就好了。

添加完成项目之后,依然需要添加一些依赖,具体如下。

[lib]
crate-type = ["cdylib", "staticlib"]

[dependencies]
flutter_rust_bridge = "1.82.3"

编写测试代码

这里,我们简单写一个对外的方法,来测试下环境是不是好的,新建一个api.rs的文件,具体内容如下,例子参考自参考2,其实随便写点啥都行,但是感觉这个例子还比较有代表性。

pub enum Platform {
    Unknown,
    Android,
    Ios,
    Windows,
    Unix,
    MacIntel,
    MacApple,
    Wasm,
}

pub fn platform() -> Platform {
    if cfg!(windows) {
        Platform::Windows
    } else if cfg!(target_os = "android") {
        Platform::Android
    } else if cfg!(target_os = "ios") {
        Platform::Ios
    } else if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
        Platform::MacApple
    } else if cfg!(target_os = "macos") {
        Platform::MacIntel
    } else if cfg!(target_family = "wasm") {
        Platform::Wasm
    } else if cfg!(unix) {
        Platform::Unix
    } else {
        Platform::Unknown
    }
}

其实,如果懒得自己做这些工作,可以直接用参考资料2当中的模板,也挺不错的。

生成桥接文件

这里,工具会帮助我们自动生成代码,来生成对应的一些桥接,首先在项目根目录,添加配置文件,否则自己要输入一坨命令,这显然是难以忍受的,具体配置文件如下。

rust_input:
  - native/src/api.rs
dart_output:
  - lib/bridge_generated.dart
c_output:
  - ios/Runner/bridge_generated.h
extra_c_output_path:
  - macos/Runner
dart_decl_output: lib/bridge_definitions.dart
dart_format_line_length: 120
wasm: true

注意,这里需要自己根据需要进行一点点调整,这里吧,我选择开启了wasm项目,所以wasm也一块给加上了,如果不需要,可以不生成。然后运行如下命令,得到自动生成的代码

flutter_rust_bridge_codegen .flutter_rust_bridge.yml

看到下面这个,就说明成功了,否则请自行检测自己有那些依赖没有装。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

这里会生成一些文件,不要删掉,不要改动他们。

测试成果

我们选择,在Flutter当中调用一下我们刚才写的Rust的代码,来测试一下成果怎么样,简单编写一个测试的代码。

// ffi.dart

import 'dart:ffi';

import 'bridge_generated.dart';
import 'bridge_definitions.dart';
export 'bridge_definitions.dart';

export 'bridge_generated.dart';
import 'dart:io' as io;

const _base = 'native';

final _dylib = io.Platform.isWindows ? '$_base.dll' : 'lib$_base.so';

final Native api =
    NativeImpl(io.Platform.isIOS || io.Platform.isMacOS ? DynamicLibrary.executable() : DynamicLibrary.open(_dylib));

// ffi_web.dart
import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';
import 'bridge_generated.web.dart';

export 'bridge_definitions.dart';

const root = 'pkg/native';
final api = NativeImpl.wasm(
  WasmModule.initialize(kind: const Modules.noModules(root: root)),
);

因为这里,我们也加了web的支持,所以说,这也写一下,其实这段代码也是在参考资料2当中借鉴出来的,在这里感谢下参考资料2的作者。接下来,就简单写一个Flutter的应用吧。

import 'dart:async';

import 'package:flutter/material.dart';
import 'ffi.dart' if (dart.library.html) 'ffi_web.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter With Rust',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter With Rust'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage{
  late Future<Platform> platform;

  @override
  void initState() {
    super.initState();
    platform = api.platform();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: FutureBuilder(
        future: platform,
        builder: (context, snap) {
          final style = Theme.of(context).textTheme.headlineMedium;
          if (snap.error != null) {
            return Tooltip(
              message: snap.error.toString(),
              child: Text('Unknown OS', style: style),
            );
          }
          if (snap.hasData) {
            final data = snap.data as Platform;
            final text = switch (data) {
              Platform.Android => 'Android',
              Platform.Ios => 'iOS',
              Platform.MacApple => 'MacOS with Apple Silicon',
              Platform.MacIntel => 'MacOS',
              Platform.Windows => 'Windows',
              Platform.Unix => 'Unix',
              Platform.Wasm => 'the Web',
              Platform.Unknown => 'Unknown OS',
            };
            return Tooltip(
              message: text,
              child: Text(text, style: style),
            );
          }
          return const Center(child: CircularProgressIndicator());
        },
      ),
    );
  }
}

Android测试

然后,我们在Android上运行一下来看看,在运行之前,需要安装cargo-ndk这个依赖,细节版本请参考官方文档,这里我用的最新的,直接装没有啥问题,低版本Rust需要降低版本。

cargo install cargo-ndk
cargo ndk -o ../android/app/src/main/jniLibs build

第二条命令是生成需要的so文件,如果不生成,会出现找不到文件的错误,运行之后,就可以得到下面的结果了,我们就搞成功了,非常的顺利,没有什么坑。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

MacOS测试

作为一个跨平台的项目,那么怎么能够只在Android平台测试呢,那么我们多尝试几个平台,接下来搞一下在MacOS上的测试,这里假设大家有MacOS的开发相关环境,并且已知MacOS开发的基础知识。

首先,我们要运行如下命令,来生成xcode项目。

cargo xcode

这里,看到生成这个文件才可以,否则就是失败了,自己检查依赖。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

然后,我们需要用xcode打开这个文件,按照如下的操作执行,

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

接下来,我们需要将我们MacOS的工程,给链接到刚才生成的native文件,首先,我们吧我们刚才的那个项目,也就是 native/native.xcodeproj 作为子工程添加到工程项目。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

然后,添加一下项目。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

添加完成的效果如下,如果不是这样,那就证明你搞错了,再来一次吧。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

然后,选中Runner,之后添加依赖,链接到我们刚才搞好的库。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

这里,选择我们刚才添加的库。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

然后,我们需要链接一下,这里选择如下

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

然后选择添加这个。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

这样,库就添加完成了,然后我们需要自己补一下头文件,对于MacOS,我们需要自行处理下,按照如下的操作。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

然后呢,我们要在`macos/Runner/AppDelegate.swift当中添加如下内容,防止优化给我们干掉代码。

import Cocoa
import FlutterMacOS

@NSApplicationMain
class AppDelegateFlutterAppDelegate {
  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
    // 这一行是新添加的
    print(dummy_method_to_enforce_bundling())
    return true
  }
}

之后,我们便可以运行Mac程序了,可以发现,在MacOS上也可以完美的运行。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

iOS测试

对于iOS来说,和MacOS的操作类似,只不过要注意,需要选择的库不一样,同样,我们简单来看一下,有关于 native/native.xcodeproj这个工程,之前已经改好了,因此不用再改了,我们要打开ios/Runner.xcodeproj这个项目。

然后,还是添加native那个项目作为子项目,这里需要选择 **-staticlib**这个,而不是之前的。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

然后,这里需要添加下头文件,在这个文件当中

// ios/Runner/Runner-Bridging-Header.h
#import "bridge_generated.h"

然后,还是在 ios/Runner/AppDelegate.swift当中添加内容。

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegateFlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  )
 -> Bool {
    // 新增这一行
    print(dummy_method_to_enforce_bundling())
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

这里,需要添加额外的设置,防止xcode给我们抹掉符号,具体如下。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

可以发现,这个也是可以的

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

Web测试

web的话,需要加入wasm的支持,因此按照如下方式安装依赖

rustup toolchain install nightly
rustup +nightly component add rust-src
rustup +nightly target add wasm32-unknown-unknown
# either of these
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
cargo install wasm-pack

然后,这里推荐使用 flutter_rust_bridge提供的方式运行项目。

dart run flutter_rust_bridge:serve

发现,也是可以的。

Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

有关于window和Linux,这里就不重复尝试了,实测也是没有问题的,到这里本文就结束了,发现Rust结合Flutter确实体验比较丝滑。

参考资料

  • https://github.com/fzyzcjy/flutter_rust_bridge[1]
  • https://github.com/Desdaemon/flutter_rust_bridge_template[2]
  • https://docs.flutter.dev/development/platform-integration/ios/c-interop#stripping-ios-symbols[3]

Reference

[1]

https://github.com/fzyzcjy/flutter_rust_bridge: https://github.com/fzyzcjy/flutter_rust_bridge

[2]

https://github.com/Desdaemon/flutter_rust_bridge_template: https://github.com/Desdaemon/flutter_rust_bridge_template

[3]

https://docs.flutter.dev/development/platform-integration/ios/c-interop#stripping-ios-symbols: https://docs.flutter.dev/development/platform-integration/ios/c-interop#stripping-ios-symbols


原文始发于微信公众号(安全后厨):Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年10月23日22:30:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Android逆向技术56——Flutter with Rust会发生什么(By LittleQ)http://cn-sec.com/archives/2138287.html

发表评论

匿名网友 填写信息