现在大多数运用Flutter的运用都是采用add2app的办法,在APP中与Flutter相关的内容主要有FlutterEngine、APP产品、资源文件。咱们能够在运用函数调用能够作为一个函数的形参商场上寻找一个接入Flutter的运用做试验。(apk可在各大运用商场下载,ipa下载能够在mac上设备Apple Configandroid手机urator 2进行),apk和ipa中flutter相关产品目录如下:

iOS包文件为ipa,下载后将其后缀重命名为z面试技巧ip进行解压,解压后Payload下即可看到运用文件夹,其间FlutterEngine、APP产品、资源文件分别在如下方位:

xxx.app
└── Frameworks
├── App.framework
│ ├── App(Dart A产品PP产品)
│ ├── Info.plist
│ ├── SC面试最佳毛遂自荐_Info
│ ├android下载软件app── _CodeSignature
│ └── flutter_assets
│       ├── flutter_assets
│       ├── AssetManifest.json
│       ├── FontManifest.json
│       ├── LICENSE
│       ├── fonts
│       ├── images
│       ├── mtf_module_info
│       └── packages
└── Flutter.framework
 ├── Flutter(FlutterEngine)
 ├── Info.plist
 ├── SC_Info
 ├── _CodeSignatur面试需要准备什么东西e
 └── icudtl.dat

Android包文件为apk,下载后将其后缀重命名字体辨认为zip进行解压,其间FlutterEng产品设计专业ine、APP产品、资源文件分别在如下方位:

xxx.apk
├── assets
│ └── flutter_aandroid下载ssets
│       └── flutter_assets
│       ├── AssetManifest.json
│       ├── FontManifest.json
│       ├── LICENSE
│       ├── fonts
│       ├── images
│       ├── mtf_module_info
│       └── packages
└── lib
└─产品设计─ armeabi
├── libapp.o(Dart APP产品)
└── libflutter.so(FlutterEngine)

FlutterEngine各个app都是运用官方或许在官方基础上进行修改,不同不多,咱们暂不关心这部分的逆向。资源文件多是图片,字体等无需逆向即可查看的资源。咱们主要关心的是运用Dart编写的事务逻辑或许某些框架代码,这部分代码在APP产品中。即:App.framework/App 或 armeabi/libapp.o这两个文件都是动态库,咱们先简略看看里边包括什么?

# 能够设备常用的 bin utils东西,如 brew update && brew install binutils
~/Downloads > objdump -t App
App:     文件格局 mach-o-arm64
SYMBOL TABLE:
0000000001697e60 g       0f SECT   02 0000 [.const] _kDartIsolateSn字体美化大师免费下载apshotData
000000000000b000 g       0f SECT   01 0000 [.text] _kDartIsolat函数调用时的实参和形参之间传递eSnapshotIns字体美化大师免费下载tructions
0000000001690440 g       0f SECT   02 0000 [.const] _kDartVmSnapshotData
0000000000006000 g       0f SECT   01 0000 [.text] _kDart字体全国VmSn函数调用时的实参和形参之间传递apshotInstructions
~/Downloads > greadelf -s libapp.so
Symbol table '.dynsym' contains 5 entries:
Num:    Value  Size Type    Bind   Vis      Ndx Name
0: 00000000     0 NOTYPE  LOCAL  DEFAULT        UND
1: 00001000 12992 FUNC    GLOBAL DEFAULT        1 _kDartVmSnapshot[...]字体设计
2: 00005000 0x127df60 FUNC    GLOBAL DEFAULT    2 _kDartIsolateSna[...]
3: 01283000 22720 OBJECT  GLOBAL DEFAULT        3 _kDartVmSnapshotData
4: 01289000 0x9fc858 OBJECT  GLOBAL DEFAULT     4 _kDartIsolateSna[...]

能够看到无论是Android仍是iOS,Dart App产品面试中都包括4个程序段。(来自httpandroid/yunoss://github.com/flutter/flutter/wiki/Flutter-engine-operation-in-AOT-Mode)

  • ‘_kDartVmSnapshotData’: 代表 isolate 之间同享的 Dart 堆 (heap) 的初始状况android下载。有助于更快地建议 Dart isolate,但不包括任产品运营主要做什么何 isolate 专属的信息。

  • ‘_kDartVmSnapshotInstructions’:包括 VM 中悉数 Dart isolate 之间同面试问题大全及答案大全享的通用例程的 AOT 指令。这种快照的体积一般十分小,而且大多会包括程序桩 (stub)。

  • ‘_kDartIsolateSnapshotData’:代表 Dart 堆的初始状况,并包括 isolate 专属的信息。

  • ‘_kDartIsolateSnapshotInstructions’:包括由 Darandroid下载软件appt isolaandroid11te 实施的 AOT 代码。

看了上面或许仍是一脸懵o((⊙﹏⊙))o,为什么分四块,Data与Instructio产品批号是生产日期吗ns,Vm与Isolate是什么?为什么运用Snapshot(快照)命名。关于这些问题,推荐一篇博客https://mrale.ph/dartvm/ 。Data与Instructions,Vm与Isolate这些概念两两组合函数调用,正好对应上面四个段。也便是VmData、VmInstructions、IsolateData、面试最佳毛遂自荐IsolateIns函数调用句子tructions。

先说一下Data与Instructions。首要咱们知道的是Flutter编产品质量法译作业在apandroid是什么手机牌子p上分为JIT和AOT办法,线上只能运用AOT办法,也便是Flutterandroid体系引入的DartVM包括了函数调用的三种方法实施AOT产函数调用句子func品的功用。为了与JIT办法兼容,DartVM采用了所谓快照的办法,即JIT作业时编译后的根本结构与A函数调用联系图OT编译的根本结构相同。将类信息、大局变量、函数指令直接以序列化的办法存在磁盘中,称为Snapshot(快照)。

怎样逆向Flutter使用

由于快照的序字体转换器列化格局针对性的为读取速率做了规划,从快照读取也大大提高代码的加载速度(创建所需函数调用联系图类信息、大局数据等,能够类比OC Runtime建议加载元类、类信息等)。开端步快照中是不包括机器代码的(面试最佳毛遂自荐即函数体内部的实施逻辑),函数调用句子func后来跟着AOT办法的开发这部分被加入到快照中了,这些后来者也便是前面说的Instructions。

怎样逆向Flutter使用

这儿要弥补的是,Instructions指的是函数调用过程可实函数调用句子行汇编指令,在.o文件中有必要放在text段里,符号为可实施(不然iOS无法加载并实施它)。类信息、大局变量这些内容能够放在data端作为一般数据被加载面试技巧和注意事项。(字节的优化50%包体积也是根据此Android,有喜爱能够看一下文章:https://juejin.im/post/6844904014170030087)。

接着产品设计专业说DartVmSnapshot 与DartIsolateSnapshot。这就触及Data虚拟机是怎样作业事务代码。虚拟是Data代码作业的载体,VM中作业的逻辑都跑在一个笼统的叫做Isolate(阻隔)的实体中。你字体大全能够把Isolate作为OC里一个带有Runloop的Thread看待(至于他们之间的联系又是一个令人头疼的面试题,这儿不展开了)。扼要来说Isolate中保护了库房变量,函数调用栈帧,用于GC、JIT等辅佐使命的子线程等, 而这儿的库房变量便是要被序列化到磁盘上的东西,即IsolateSnapshot。此外像dart预置的大局政策,比方null,true,falAndroidse等等等是由VM产品代理Isolate管理的,这些东西需序列化后即VmSnapshot。

怎样逆向Flutter使用

到这儿大致了解Flutter APP产品中的结构。那怎样读取他们呢?咱们能够从clusterandroid是什么手机牌子ed_snapshot.android11cc函数调用的三种方法中的Fu面试问题llSnapshotReader:: 函数看起,看他是怎样反序列化的。


void Deserializer::ReadIs字体管家olateSnapshot(Object面试毛遂自荐范文通用Sto产品质量法re* ob函数调用句子funcject_store) {
Array& refs = Array::Handle();
Prepare();
{
NoSafepointScope no_safepoint;
HeapLocker hl(thread(), heap_->old_space());
// N.B.: Skipping index 0 becau产品司理se ref 0 is illegal.产品质量法
const Array& base_objects = Object::vm_isolate_snapshot_obj面试技巧ect_table();
for (字体管家intptr_t产品代理 i = 1; i < base_objects.Length(); i++) {
AddBaseObjeandroid什么意思ct(b产品质量法ase_objects.At(i));
}
Deserialize();
// Read roots.
RawObject** from = object_store->froandroid11m();
RawObject** to = object_store->to_snapshot(kind产品质量法_);
for (RawO字体全国bject** p = from; p <= to; p++) {
*p = ReadRef();
}
#if defined(DEBUG)
int32_t section_marker = Read<int32_t>();
ASSERT(section_marker == kSecti面试技巧和注意事项onMarker);
#endif
refs = refs_;
refs_ = NULL;
}
thre字体大全ad()->isolate()->class_table()->CopySizesFromClassObjects();
heap_->old_space(产品)->EvaluateSnapshotLoad();
#if defined(DEBUG)
Isolate* isolate = thread()->isola面试最佳毛遂自荐te();
isolate->ValidateClassTable();android什么意思
isolate-函数调用句子func>heap()->Verif产品批号是生产日期吗y();
#enandroid平板电脑价格d产品批号是生产日期吗if
for (intptr_t i = 0; i < num_clusters_; i++) {
clusters_[i]->PostLo字体辨认ad(refs, kind_, zone产品运营_);
}
// Setup native resolver for bootstrap impl.
Bootstrap::SetupNativeResolver();
}

要看懂这部分也是十分吃力,另一个大神的产品设计专业剖析文字体美化大师免费下载章或许会为咱们带来许多启示:https://blog.tst.sh/reverse-engineering-flutter-apps-part-1/

咱们要看怎样读取RawObject政策

怎样逆向Flutter使用

每个政策均以包括以下符号的uint32_t开端:

怎样逆向Flutter使用

原则上咱们自己能够写一个读取的程序进行剖析,但是网上有一个运用Python写好的读取程序(只支撑读取ELF格局字体文件,也便是只支撑Android包产品的面试问题大全及答案大全剖析):httpandroid下载s://android是什么手机牌子gandroid下载软件appithub.com/hdw09/darter 根据这个读取东西供给的API咱们能够写一个导出运用悉数类界说的东西。

from darter.file import parse_elf_snapshot, parse_appjit_snapshot
from darter.asm.base import populate_native_references
import re
from co面试毛遂自荐范文通用llections import defaultdict
import os
import shuti面试技巧l
def get_funciont(fun_i产品批号是生产日期吗ndex, s, span=False):
spanStr = ''android下载
if span:
spanStr = '    '
fun_str = 'n'+spanS面试毛遂自荐范文通用tr+'// 函数索引:' + '{0}'.format(fun_index)+'n'
return面试毛遂自荐3分钟通用Typ函数调用句子funceStr = ''
if '_class' in s.refs[fun_index].x['resandroid11ult_type'].x.keys():
returnTypeStr = s.refs[fu产品设计n_index].x字体转换器['result_t面试ype'].x['_class'].x['name'].x['value']
elif 'name' i字体大全n s.refs[fun_index].x['result_type'].x.keys(字体):
ret字体美化大师urnTypeSt面试最佳毛遂自荐r = str(s.refs[fun_index].x['result_type'])
else:
returnTypeStr = s.refs[android手机fun_index].x['result_type'].x['value']
fun_str = fun_str+spanStr + returnTyp字体大小怎样调eStr
fun_str = fun_str + ' ' + s.refs[fun_index].x['name'].x['value']+android下载安装'('
parameterCount面试毛遂自荐3分钟通用 = 0
if type(s.refs[fun_index].x['android什么意思parameter_types'].x['value']) != type(''):
for parameterName in s.refs[fun_index].x['parameter_names'].x['value']:
parType = ''
if '_class' in s.refs[fun_index].x['parameter_types'].x['valuandroid/yunose'][paramet产品设计erCount].x.keys():
parType = s.refs[fun_index].x['parameter_types'].x['value'][parameterCount].x面试技巧和注意事项['_class'].x['name'函数调用句子].x['valu函数调用的三种方法e']
else:
parType = s.refs[fun函数调用时的实参和形参之间传递_index].x['parameter_types']函数调用联系图.x['value'][parameterCount].x['val函数调用能够ue']
fun_str = fun_str + parType + ' '
fun_str = fun_str + parameterName面试需要准备什么东西.x['value'] + ', '
parameterCount字体美化大师 = parameterCount + 1
fun_str = fun_str + ') n'+spanStr+'{ n'
for nrefsItem in s.refs[fun_index].x['code'].x['nrefs']:
fun_str = fun_str + spanStr + '    {0}'.format(nrefsItem) + 'n'
fun_str = fun_str + spanStr+'}'
ret产品批号是生产日期吗ur函数调用数组n fun_str
def get_classDis(clas_index, s):
class_str = 'n// 类索引:android下载' + '{0}'.format(clas_index)+' 运用s.refs[xxxx].x跟查n'
superName = ''
if '_class' in s.refs[clas_index].x['super_type'].x.keys(面试毛遂自荐范文通用):
superName = s.randroid什么意思efs[clas_in函数调用数组dex].x['super_type'].x['_class'].x['name'].x['value']
else:
superName = s.r函数调用能够作为一个函数的形参efs[clas_index].x['super_type'].x['value']
class_str = class_str + 
'class {0} : {1} {2}n'.form产品批号是生产日期吗at(面试毛遂自荐范文通用
s.refs[clas_index].x['name'].x['value'], superName, '{')
if type(s.refs[clas产品质量法_index].x['functions'].x['value']) != type('字体大小怎样调'):
for fun in s.refs[cla产品密钥在哪里能找到s_index]字体大小怎样调.x['functions'].x['value']:
class_str = class_str+'n'+get_funciont(fun.ref, s, True)
return class_str+'nn}'
def get_landroid11ob_class(lib, s):
all字体转换器_class = ''
for item in lib.src:
if 'name' in item[0].x.keys():
all_class = all_class + get_classDis(item[0].ref, s) + 'n'
if '类索引' in all_class:
return all_claandroid下载安装ss
else:
retur面试毛遂自荐3分钟通用n '没有取得任何信息'
def show_lob_class(lib, s):
print(get_lob_class(lib, s))
def writeStringInPackageFile(packageFile, c产品运营ontent):
packageFile = packageFile.replace('dart:', 'package:dart/')
filename = packageFile.replace('package:', 'out/')
filePath = filename[0:filename.字体大全rfind('/')]
content = '// {0} n'.format(packageFile)+content
if os.path.exists(filePath) == False:
os.makedirs(filePath)
file = open(filename, 'w')
file.write(content)
fil函数调用中的参数太多e.close()
def getFiles(elfFile, filter):
s = parse_elf_snapshot(elfFile)
populate_natandroid下载ive_references(s)
allLibrary = sorted(s.getrefs('Library'),
key=lambda x: x.x['url'].x['value'])
for tempLibrary in allLibrary:
name = tempLibrary.x['url字体下载'].x['value']
if filter in name:字体
print(name + '初步生成....')
writeStringInPackageFile(
name, get_lob_class(s.strings[name]产品.src[1][0], s))
print(name + '生成成功✅')
# 初步实施
getFiles('samples/arm-app.so', '')

这个脚本最终会提取悉数指定文件的源码,其间对友商app其间一个类的导出结果如下:

怎样逆向Flutter使用

其间标明了类政策 与函数的索引,能够在控制台运用s.refs[xxxxx].x继续跟查。