Flutter逆向技术的探讨与研究(2)

Flutter逆向技术的探讨与研究(2)

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

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

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

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

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

0xdcdcf5f5 在这里被定义为`kMagicValue

`

  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是个枚举类 大概就是当前的编译快照类型

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 把这里读出来试试

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)

输出

f5f5dcdc
fed20b0000000000
0300000000000000

好像有点对得上了

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

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

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

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

 SnapshotHeaderReader(snapshot->kind(),
                             snapshot->Addr(),
                             snapshot->length())

接下来是两个字段一个是

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

features 字段在 VerifyFeatures() 里面长度

他的长度是在

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

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

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

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

我们可以依次读出来

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)

输出:

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语言,再回头来翻译这份代码。

  template <typename T = intptr_t>

  T ReadUnsigned() {

    return Read<T>(kEndUnsignedByteMarker);

  }