Pull to refresh
60.64

Пасхалка в APK-файлах: что такое Frosting

Reading time 28 min
Views 4.1K


Автор: Константин Молодяков


Структура файла — увлекательный мир со своими историей, тайнами и собственным цирком уродов, где выступают костыльные решения. Если в ней покопаться, можно найти много интересного.


Я наткнулся на одну особенность APK-файлов — специальную подпись с особым блоком метаданных, Frosting. Она позволяет однозначно определить, распространялся ли файл через Google Play. Эта подпись будет полезна для антивирусных вендоров и песочниц при анализе вредоносов. Кроме того, она может помочь криминалистам при поиске источника файла.


Информации об этом практически нет. Удалось найти только раздел Security metadata in early 2018 в Android Developers Blog и утилиту Avast, которая позволяет проверить данную подпись. Я решил изучить эту штуку, проверить корректность предположений разработчиков Avast о содержании Frosting-блока и поделиться своими выводами.


Frosting и APK Signing Block


Google использует специальную подпись APK-файлов при публикации приложений в Google Play. Эта подпись лежит в APK Signing Block, который находится перед центральной директорией ZIP-файла и после его основного содержимого:

Для идентификации APK Signing Block используется magic — APK Sig Block 42. Внутри блока подписи могут лежать другие блоки, предназначение которых определяется 4-байтовым ID. Получается расширение ZIP-формата с обратной совместимостью. Если интересно почитать подробнее или увидеть исходники, метод ApkSigningBlockUtils.findSignature описан тут.


Возьмем какой-нибудь файл, например 2124948e2b7897cd6fbbe5fbd655c26d. Посмотреть идентификаторы блоков, содержащихся в APK Signing Block, можно с помощью androguard:


from androguard.core.bytecodes import apk
apk_obj = apk.APK("2124948e2b7897cd6fbbe5fbd655c26d.apk")
apk_obj.parse_v2_v3_signature()
print(["0x%X" % key for key in apk_obj._v2_blocks.keys()])

['0x7109871A', '0x2146444E']

Существует несколько блоков с разными индентификаторами, которые официально описаны в документации:



Некоторые блоки можно найти в исходниках Android:


  • 0x42726577 (VERITY_PADDING_BLOCK_ID) — блок, используемый для нулевого выравнивающего блока;
  • 0x6dff800d (SOURCE_STAMP_BLOCK_ID) — относительно новый вид блоков.

Встречаются и другие блоки:


  • 0x504b4453 (DEPENDENCY_INFO_BLOCK_ID) — блок, в котором, по всей видимости, содержится метаинформация о зависимостях, сохраняемая плагином Android Gradle для определения проблем с ними;
  • 0x71777777 (APK_CHANNEL_BLOCK_ID) — блок китайской приблуды Walle для сборки, который содержит JSON с именем канала;
  • 0xff3b5998 — нулевой блок, который встретился мне в файле — найти какую-либо информацию о нем я не смог;
  • 0x2146444e — блок с необходимой метаинформацией от Google Play.

Frosting и «Play Маркет»


Вернемся к анализу рассматриваемого блока 0x2146444e. Для начала следует изучить внутренности приложения «Play Маркет».


.method public static b(ByteBuffer)ByteBuffer
        .registers 2
    00000000  invoke-static       bny->a(ByteBuffer)aea, p0
    00000006  move-result-object  p0
    00000008  const               v0, 0x2146444E
    0000000E  invoke-virtual      aea->a(I)Object, p0, v0
    00000014  move-result-object  p0
    00000016  check-cast          p0, bnx
    0000001A  if-eqz              p0, :00000024
    0000001E  iget-object         p0, p0, bnx->a:ByteBuffer
    00000022  return-object       p0
    00000024  new-instance        p0, SigBlockUtil$BlockNotFoundException
    00000028  const-string        v0, "Block entry id (go/apk-structure-glossary) "
                                      "not present in APK Signing Block"
    0000002C  invoke-direct       SigBlockUtil$BlockNotFoundException->
                                      <init>(String)V, p0, v0
    00000032  throw               p0
.end method

Интересующий нас идентификатор обнаружен в двух местах. Смотрим глубже. Довольно быстро находим класс, отвечающий за разбор блока. Здесь же первый раз среди констант появляется название Frosting-блока:


public enum aysn implements avto {
    UNKNOWN(0),
    SUCCESS(81),
    NO_FROSTING_BLOCK(1),
    FROSTING_BLOCK_TOO_SHORT(2),
    BAD_SIGNED_DATA_LENGTH_VARINT(3),
    NON_POSITIVE_SIGNED_DATA_LENGTH(4),
    SIGNED_DATA_LENGTH_TOO_LONG(5),
    BAD_FROSTING_LENGTH_VARINT(6),
    NON_POSITIVE_FROSTING_LENGTH(7),
    FROSTING_LENGTH_BEYOND_SIGNED_DATA(8),
    FROSTING_LENGTH_BEYOND_BLOCK(9),
    MALFORMED_FROSTING(10),
    // ...
    INSTALLER_NO_ACCOUNT_WITH_MATCHING_REGION(74);
    // ...
}

Я сравнил разные версии приложения «Play Маркет» и заметил следующее: код, отвечающий за разбор такого вида подписи, появился примерно в январе 2018 года вместе с выходом версии 8.6.X. Блок с метаданными Frosting существовал и раньше, но именно в этот период он принял тот вид, в котором существует сейчас.


Для разбора данных нам понадобится примитив чтения 4-байтового числа. Схема представляет собой стандартный varint без каких-либо ухищрений с отрицательными числами:


private static int read_int32(ByteBuffer arg2) {
    int v0 = arg2.get();
    if(v0 >= 0) {
        return v0;
    }

    int v0_1 = v0 & 0x7F;
    int v1 = arg2.get();
    if(v1 >= 0) {
        return v1 << 7 | v0_1;
    }

    v0_1 |= (v1 & 0x7F) << 7;
    int v1_1 = arg2.get();
    if(v1_1 >= 0) {
        return v1_1 << 14 | v0_1;
    }

    v0_1 |= (v1_1 & 0x7F) << 14;
    int v1_2 = arg2.get();
    if(v1_2 >= 0) {
        return v1_2 << 21 | v0_1;
    }

    int v2 = arg2.get();
    int v0_2 = v0_1 | (v1_2 & 0x7F) << 21 | v2 << 28;
    if(v2 >= 0) {
        return v0_2;
    }

    throw new IllegalArgumentException();
}

Функция разбора блока довольно большая, хоть и устроена просто. Она позволяет разобраться в самой структуре данных:


{
    var_int32 size_signed_data,
    var_int32 size_frosting,
    byte frosting[size_frosting],
    var_int32 size_validation_sequence,
    array validation_sequence {
        var_int32 size_validation_data,
        var_int32 validation_strategy,
        var_int32 signing_key_index,
        byte sha256[0x20]},
    var_int32 size_signature_sequence,
    array signature_sequence {
        var_int32 size_signature,
        byte signature[size_signature]}}

Для проверки подписи используются хеш и ключ первого поля из последовательности validation_sequence, у которого validation_strategy равен нулю. Сама подпись забирается из последовательности signature_sequence с таким же порядковым номером, как у записи из validation_sequence. На рисунке ниже представлен поясняющий псевдокод:


def get_signing_data(frosting_block):
    for i, validation in enumerate(frosting_block.validation_sequence):
        if validation.validation_strategy != 0:
            continue
        return (
            validation.sha256, validation.signing_key_index,
            frosting_block.signature_sequence[i].signature)
    raise AttributeError()

Значение signing_key_index указывает на индекс в массиве finsky.peer_app_sharing_api.frosting_public_keys, который определен следующим образом и пока содержит только один ключ:


gyd.iH = arip.a(
    "finsky.peer_app_sharing_api.min_tos_version", v8);
gyd.iI = arip.a(
    "finsky.peer_app_sharing_api.frosting_public_keys",
    "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZH2+1+E07dnErAD3L6BbTnaohU0bbXriNlJI7VxJU+LjdSwPyXR5pomARAMoyPkMksLz/gitUPtFuJoPL2ziEw==");
gyd.iJ = arip.a(
    "finsky.peer_app_sharing_api.startup_package_blacklist",
    "com.android.vending,com.google.android.gms,com.android.providers.downloads");
gyd.iK = arip.a(
    "finsky.frosting_only_update_time_ms", Long.valueOf(TimeUnit.DAYS.toMillis(30L)));

Подписываются данные размером size_signed_data, начиная с переменной size_frosting, алгоритмом ECDSA_SHA256. При этом подписываемые данные содержат SHA-256 от данных файла:


1) данные от начала файла до блока подписи;


2) данные от central directory до конца end of central directory, с заменой в end of central directory значения поля offset of start of central with respect to the starting disk number на оффсет блока подписи.


Если есть блок подписи схемы версии 2, то он вставляется между данными из пунктов 1 и 2 с добавлением APK_SIGNATURE_SCHEME_V2_BLOCK_ID перед ним.

Функция, вычисляющая хеш в приложении «Play Маркет», выглядит так:


private static byte[] get_frosting_hash(RandomAccessFile f_apk,
         long offset_signing_block, ByteBuffer signature_scheme_v2_block,
         long offset_zip_central_dir, long size_from_central_dir_to_end_central_dir,
         ByteBuffer end_central_dir) {
    MessageDigest v0;
    try {
        v0 = MessageDigest.getInstance("SHA-256");
    }
    catch(NoSuchAlgorithmException unused_ex) {
        throw new FrostingUtil.FailureException(aysn.N);  // NO_SHA_256_ALGORITHM
    }

    mcc.update_digest(v0, f_apk, 0L, offset_signing_block);
    if(signature_scheme_v2_block != null) {
        v0.update(mcc.a);
        v0.update(signature_scheme_v2_block);
    }

    mcc.update_digest(v0, f_apk, offset_zip_central_dir,
            size_from_central_dir_to_end_central_dir);
    bnz.a(end_central_dir, offset_signing_block);
    end_central_dir.position(end_central_dir.position());
    end_central_dir.limit(end_central_dir.limit());
    v0.update(end_central_dir);
    return v0.digest();
}

Frosting и ProtoBuf


Этой информации достаточно, чтобы проверить валидность подписи. Но, увы, мне так и не удалось узнать, что скрывается в данных Frosting-блока. У меня получилось лишь определить, что данные имеют формат ProtoBuf и могут сильно отличаться по размеру и наличию полей в зависимости от файла.


Обычно декодированные без схемы данные выглядят так (4b005c9e9ea0731330a757fcf3abeb6e):


cat ./ru.sberbankmobile_11.1.0_2020072413.protobuf | ./protodec -p

{
  "1:0:varint": 2,
  "2:1:varint": 0,
  "3:2:varint": 1,
  "4:3:varint": 1603811598348,
  "5:4:embedded": {
    "8:0:embedded": {
      "1:0:embedded": {
        "1:0:varint": 21
      },
      "6:1:varint": 3
    },
    "9:1:embedded": {
      "1:0:embedded": {
        "1:0:varint": 2020072413,
        "4:1:varint": 3
      },
      "2:1:embedded": {
        "1:0:varint": 2020072414,
        "4:1:varint": 5
      }
    },
    "10:2:embedded": {
      "1:0:bytes": [
        255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 7,
        0, 40, 0, 16, 0, 0, 80, 5, 16, 64, 0, 56
      ]
    }
  },
  "8:5:varint": 1,
  "9:6:varint": 2
}

Но встречаются экземпляры (471c589acc800135eb318057c43a8068), содержащие под пятьсот полей.


Скрытый текст
{
  "1:0:varint": 1,
  "2:1:varint": 1,
  "3:2:varint": 1,
  "4:3:varint": 1593452906098,
  "5:4:embedded": {
    "7:0:embedded": {
      "1:0:varint": 1,
      "2:1:varint": 1
    },
    "8:1:embedded": {
      "1:0:embedded": {
        "1:0:varint": 16
      },
      "6:1:varint": 3,
      "6:2:varint": 2
    },
    "9:2:embedded": {
      "1:0:embedded": {
        "1:0:varint": 2021505050,
        "4:1:varint": 3,
        "4:2:varint": 2
      }
    },
    "10:3:embedded": {
      "1:0:bytes": [
        221, 255, 227, 239, 247, 127, 255, 191, 239, 191, 255, 255, 255, 255,
        247, 255, 255, 0, 0, 8, 0, 16, 0, 0, 16, 5, 16, 64, 0, 32],
      "3:1:embedded": {
        "1:0:bytes": [
          137, 204, 247, 126, 103, 225, 96, 185, 11, 67, 239, 227, 193, 247,
          248, 68, 8, 2, 37, 20, 197, 120, 249, 112, 81, 240, 131, 124, 231,
          64, 45, 116, 60, 212, 47, 211, 175, 84, 218, 140, 61, 140, 116, 14,
          9, 38, 64, 21, 87, 196, 128, 228, 201, 237, 248, 67, 96, 229, 131,
          79, 217, 94, 223, 232, 73, 222, 177, 132, 162, 191, 144, 84, 83, 77,
          253, 70, 207, 180, 53, 131, 75, 2, 111, 84, 212, 4, 33, 100, 160, 78,
          253, 54, 63, 120, 67, 18, 92, 196, 101, 214, 245, 149, 11, 217, 102,
          93, 243, 158, 87, 133, 135, 85, 179, 175, 58, 242, 217, 52, 37, 128,
          81, 76, 10, 113, 96, 205, 150, 253, 12, 105, 74, 1, 25, 146, 160,
          126, 93, 196, 179, 143, 145, 106, 135, 242, 136, 186, 96, 164, 61,
          11, 56, 229, 113, 104, 68, 162, 179, 105, 25, 125, 27, 43, 162, 94,
          238, 237, 75, 89, 0, 112, 98, 49, 129, 49, 208, 89, 163, 66, 174,
          119, 27, 135, 109, 105, 204],
        "2:1:varint": 13
      }
    },
    "12:4:embedded": {
      "1:0:embedded": {
        "5:0:varint": 21
      },
      "2:1:embedded": {
        "1:0:varint": 0,
        "2:1:embedded": {
          "1:0:bytes": [
            41, 93, 201, 211, 27, 15, 203, 207, 160, 84, 10, 4, 65, 194, 92,
            146, 191, 221, 207, 134, 150, 216, 77, 234, 223, 53, 187, 49, 207,
            136, 84, 82]
        },
        "3:2:embedded": {
          "1:0:bytes": [
            80, 168, 41, 12, 177, 59, 101, 235, 150, 116, 174, 248, 213, 250,
            72, 228, 35, 56, 11, 184, 197, 36, 206, 168, 225, 19, 221, 82, 213,
            106, 206, 248],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 120
            }
          }
        },
        "3:3:embedded": {
          "1:0:bytes": [
            59, 234, 46, 139, 75, 154, 134, 17, 78, 53, 232, 182, 38, 151, 51,
            63, 38, 71, 1, 189, 112, 252, 157, 201, 177, 179, 163, 159, 188,
            22, 181, 221],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 160
            }
          }
        },
        "3:4:embedded": {
          "1:0:bytes": [
            202, 210, 137, 99, 138, 209, 74, 181, 118, 190, 8, 18, 68, 86, 137,
            151, 223, 217, 226, 19, 248, 109, 240, 206, 216, 31, 232, 18, 87,
            167, 17, 251],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 240
            }
          }
        },
        "3:5:embedded": {
          "1:0:bytes": [
            191, 119, 224, 30, 167, 161, 4, 135, 44, 155, 92, 208, 26, 168,
            120, 198, 195, 65, 125, 110, 58, 168, 92, 171, 56, 41, 131, 172,
            176, 171, 78, 223],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 320
            }
          }
        },
        "3:6:embedded": {
          "1:0:bytes": [
            246, 143, 161, 148, 32, 191, 55, 116, 35, 71, 23, 31, 83, 35, 218,
            162, 116, 40, 111, 227, 122, 3, 151, 57, 45, 54, 156, 94, 171, 146,
            185, 175],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 480
            }
          }
        },
        "3:7:embedded": {
          "1:0:bytes": [
            5, 217, 66, 174, 71, 16, 113, 53, 143, 20, 129, 142, 83, 16, 107,
            217, 105, 193, 85, 234, 236, 46, 45, 168, 7, 17, 71, 171, 18, 239,
            131, 23],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 640
            }
          }
        },
        "3:8:embedded": {
          "1:0:bytes": [
            134, 163, 146, 36, 137, 172, 95, 238, 205, 214, 71, 99, 209, 190,
            16, 59, 205, 59, 201, 2, 146, 43, 117, 131, 131, 218, 64, 251, 108,
            217, 37, 141],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 213
            }
          }
        },
        "3:9:embedded": {
          "1:0:bytes": [
            186, 26, 67, 178, 23, 52, 226, 60, 224, 196, 139, 119, 120, 246,
            20, 110, 238, 52, 171, 50, 107, 40, 225, 89, 86, 93, 183, 41, 195,
            150, 1, 234],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 7
            }
          }
        },
        "3:10:embedded": {
          "1:0:bytes": [
            58, 32, 81, 63, 166, 190, 81, 128, 63, 140, 253, 185, 32, 231, 65,
            64, 145, 144, 158, 160, 114, 51, 147, 56, 145, 78, 131, 124, 155,
            244, 135, 29],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 47
            }
          }
        },
        "3:11:embedded": {
          "1:0:bytes": [
            208, 138, 65, 103, 12, 44, 60, 179, 81, 117, 125, 125, 32, 171, 58,
            255, 61, 9, 184, 59, 17, 165, 38, 250, 2, 126, 131, 206, 204, 106,
            121, 122],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 172
            }
          }
        },
        "3:12:embedded": {
          "1:0:bytes": [
            31, 249, 92, 139, 0, 179, 127, 14, 76, 18, 118, 130, 116, 231, 107,
            180, 104, 172, 152, 12, 126, 119, 18, 158, 162, 145, 126, 39, 92,
            184, 71, 29],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 148
            }
          }
        },
        "3:13:embedded": {
          "1:0:bytes": [
            215, 70, 132, 253, 56, 142, 20, 226, 80, 118, 251, 124, 96, 236,
            23, 198, 249, 38, 100, 213, 16, 125, 232, 138, 142, 127, 236, 127,
            185, 25, 114, 190],
          "2:1:embedded": {
            "7:0:embedded": {
              "1:0:string": "IW"
            }
          }
        },
        "3:14:embedded": {
          "1:0:bytes": [
            87, 151, 187, 223, 182, 225, 35, 238, 176, 44, 82, 149, 122, 132,
            165, 219, 225, 29, 73, 188, 200, 85, 139, 102, 160, 115, 38, 107,
            248, 236, 198, 127],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 153
            }
          }
        },
        "3:15:embedded": {
          "1:0:bytes": [
            41, 181, 59, 170, 70, 192, 248, 215, 162, 173, 176, 230, 98, 201,
            85, 97, 46, 213, 204, 180, 97, 160, 104, 131, 96, 116, 115, 239,
            75, 4, 152, 127],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 171
            }
          }
        },
        "3:16:embedded": {
          "1:0:bytes": [
            66, 31, 252, 95, 240, 235, 159, 130, 37, 247, 203, 210, 165, 40, 2,
            37, 157, 33, 78, 114, 102, 214, 7, 15, 128, 103, 91, 63, 138, 113,
            125, 119],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 3
            }
          }
        },
        "3:17:embedded": {
          "1:0:bytes": [
            38, 209, 2, 170, 201, 97, 61, 107, 59, 193, 146, 187, 51, 241, 22,
            232, 147, 33, 169, 77, 71, 109, 213, 77, 47, 247, 160, 158, 111,
            206, 156, 243],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 184
            }
          }
        },
        "3:18:embedded": {
          "1:0:bytes": [
            195, 229, 130, 114, 114, 109, 5, 1, 40, 156, 47, 239, 0, 169, 239,
            211, 98, 138, 113, 182, 234, 23, 214, 125, 49, 107, 142, 168, 175,
            253, 223, 124],
          "2:1:embedded": {
            "7:0:embedded": {
              "1:0:string": "IN"
            }
          }
        },
        "3:19:embedded": {
          "1:0:bytes": [
            53, 252, 95, 223, 136, 114, 75, 101, 122, 251, 97, 128, 49, 203,
            183, 223, 33, 50, 56, 209, 198, 238, 135, 15, 85, 128, 142, 242,
            221, 17, 110, 219],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 77
            }
          }
        },
        "3:20:embedded": {
          "1:0:bytes": [
            31, 231, 69, 193, 155, 115, 41, 39, 125, 98, 164, 106, 101, 40, 15,
            168, 63, 161, 40, 158, 119, 56, 170, 131, 97, 143, 204, 117, 219,
            228, 115, 58],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 51
            }
          }
        },
        "3:21:embedded": {
          "1:0:bytes": [
            58, 114, 14, 110, 167, 28, 66, 253, 106, 5, 106, 130, 219, 199,
            234, 73, 126, 0, 63, 102, 153, 172, 52, 224, 22, 145, 84, 42, 74,
            216, 210, 58],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 154
            }
          }
        },
        "3:22:embedded": {
          "1:0:bytes": [
            3, 198, 55, 89, 63, 195, 67, 117, 23, 19, 208, 6, 64, 61, 55, 60,
            106, 216, 150, 133, 175, 51, 211, 254, 106, 150, 250, 240, 10, 49,
            163, 47],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 84
            }
          }
        },
        "3:23:embedded": {
          "1:0:bytes": [
            43, 113, 17, 252, 89, 90, 79, 80, 158, 159, 123, 186, 207, 137, 84,
            186, 68, 155, 105, 111, 176, 215, 70, 107, 51, 237, 73, 155, 242,
            122, 10, 46],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 325
            }
          }
        },
        "3:24:embedded": {
          "1:0:bytes": [
            163, 118, 101, 102, 1, 115, 201, 144, 237, 239, 117, 79, 163, 127,
            173, 149, 33, 211, 90, 111, 82, 50, 146, 101, 80, 30, 22, 112,
            153, 164, 19, 150],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 258
            }
          }
        },
        "3:25:embedded": {
          "1:0:bytes": [
            11, 171, 219, 11, 212, 240, 116, 80, 201, 168, 63, 75, 188, 168,
            236, 220, 108, 157, 49, 226, 17, 158, 105, 188, 44, 180, 67, 196,
            36, 31, 46, 149],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 161
            }
          }
        },
        "3:26:embedded": {
          "1:0:bytes": [
            233, 52, 162, 8, 5, 80, 139, 147, 172, 124, 252, 124, 75, 146, 182,
            53, 109, 29, 220, 18, 52, 120, 53, 83, 255, 138, 143, 39, 194, 61,
            163, 196],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 46
            }
          }
        },
        "3:27:embedded": {
          "1:0:bytes": [
            82, 61, 18, 192, 210, 218, 157, 38, 65, 86, 39, 30, 138, 32, 248,
            114, 10, 148, 210, 251, 130, 23, 54, 116, 104, 206, 141, 102, 169,
            191, 5, 233],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 38
            }
          }
        },
        "3:28:embedded": {
          "1:0:bytes": [
            47, 251, 190, 153, 104, 136, 52, 169, 146, 57, 29, 6, 153, 167, 3,
            209, 5, 30, 100, 215, 240, 47, 96, 103, 114, 164, 131, 197, 69,
            112, 4, 86],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 129
            }
          }
        },
        "3:29:embedded": {
          "1:0:bytes": [
            93, 192, 14, 10, 50, 59, 229, 14, 140, 132, 196, 12, 219, 149, 215,
            224, 125, 6, 139, 61, 6, 144, 255, 96, 5, 37, 216, 91, 137, 135,
            41, 24],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 25
            }
          }
        },
        "3:30:embedded": {
          "1:0:bytes": [
            10, 2, 142, 220, 179, 122, 72, 30, 24, 127, 28, 65, 31, 28, 73,
            126, 198, 238, 62, 156, 228, 87, 163, 9, 38, 116, 106, 48, 25,
            152, 159, 179],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 126
            }
          }
        },
        "3:31:embedded": {
          "1:0:bytes": [
            81, 12, 199, 94, 25, 57, 186, 111, 6, 142, 64, 231, 47, 149, 116,
            21, 53, 34, 89, 104, 13, 47, 184, 121, 38, 4, 206, 64, 179, 247,
            20, 137],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 156
            }
          }
        },
        "3:32:embedded": {
          "1:0:bytes": [
            171, 95, 184, 6, 120, 203, 22, 123, 134, 45, 181, 225, 90, 186,
            233, 210, 8, 55, 43, 48, 169, 47, 10, 200, 161, 216, 118, 98, 61,
            215, 124, 135],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 158
            }
          }
        },
        "3:33:embedded": {
          "1:0:bytes": [
            198, 24, 206, 30, 88, 136, 6, 128, 184, 53, 150, 247, 25, 79, 56,
            60, 81, 143, 13, 123, 107, 35, 86, 162, 122, 7, 216, 27, 27, 249,
            19, 47],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 63
            }
          }
        },
        "3:34:embedded": {
          "1:0:bytes": [
            230, 93, 108, 31, 194, 183, 82, 253, 244, 34, 6, 1, 7, 69, 80, 147,
            131, 89, 158, 29, 236, 115, 92, 196, 44, 178, 254, 238, 121, 246,
            113, 68],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 104
            }
          }
        },
        "3:35:embedded": {
          "1:0:bytes": [
            147, 204, 39, 33, 249, 108, 184, 249, 48, 14, 165, 120, 66, 9, 137,
            134, 5, 48, 106, 48, 105, 140, 144, 159, 125, 179, 124, 71, 158,
            117, 131, 210],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 19
            }
          }
        },
        "3:36:embedded": {
          "1:0:bytes": [
            89, 255, 33, 10, 191, 177, 183, 189, 245, 158, 109, 205, 126, 163,
            104, 71, 57, 35, 124, 14, 130, 83, 188, 213, 129, 96, 249, 122, 39,
            106, 120, 195],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 80
            }
          }
        },
        "3:37:embedded": {
          "1:0:bytes": [
            105, 92, 221, 66, 185, 181, 94, 19, 30, 129, 85, 145, 196, 110, 14,
            125, 216, 251, 11, 186, 138, 194, 135, 243, 1, 172, 32, 128, 159,
            113, 84, 87],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 106
            }
          }
        },
        "3:38:embedded": {
          "1:0:bytes": [
            157, 183, 189, 153, 219, 24, 43, 100, 235, 0, 132, 119, 215, 108,
            236, 153, 22, 241, 252, 211, 231, 116, 33, 113, 123, 237, 138, 202,
            213, 153, 43, 88],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 123
            }
          }
        },
        "3:39:embedded": {
          "1:0:bytes": [
            146, 229, 59, 43, 145, 105, 186, 201, 142, 14, 158, 90, 5, 28, 230,
            197, 134, 18, 13, 219, 74, 209, 84, 214, 210, 54, 70, 1, 56, 31,
            218, 54],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 58
            }
          }
        },
        "3:40:embedded": {
          "1:0:bytes": [
            220, 242, 61, 79, 217, 248, 85, 208, 85, 163, 104, 176, 88, 2, 114,
            108, 131, 202, 204, 53, 110, 75, 239, 56, 136, 67, 248, 247, 12,
            63, 191, 12],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 175
            }
          }
        },
        "3:41:embedded": {
          "1:0:bytes": [
            71, 68, 176, 15, 211, 98, 59, 27, 187, 227, 14, 91, 53, 120, 129,
            50, 108, 107, 103, 66, 252, 217, 178, 77, 184, 147, 91, 90, 19,
            111, 128, 53],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 134
            }
          }
        },
        "3:42:embedded": {
          "1:0:bytes": [
            201, 51, 220, 118, 187, 125, 87, 7, 246, 185, 155, 52, 220, 28, 12,
            90, 48, 123, 202, 135, 233, 18, 3, 137, 10, 222, 223, 206, 111,
            196, 255, 235],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 78
            }
          }
        },
        "3:43:embedded": {
          "1:0:bytes": [
            144, 123, 192, 106, 90, 212, 71, 96, 188, 5, 46, 223, 100, 12, 58,
            99, 141, 127, 17, 14, 181, 44, 129, 224, 57, 134, 157, 34, 245, 78,
            63, 60],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 130
            }
          }
        },
        "3:44:embedded": {
          "1:0:bytes": [
            21, 33, 78, 136, 74, 131, 86, 48, 170, 99, 67, 146, 12, 42, 119,
            249, 70, 198, 221, 127, 241, 175, 42, 0, 12, 66, 71, 172, 59, 17,
            27, 228],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 56
            }
          }
        },
        "3:45:embedded": {
          "1:0:bytes": [
            45, 178, 69, 5, 175, 52, 44, 90, 190, 94, 100, 180, 238, 153, 189,
            58, 248, 181, 189, 134, 151, 53, 68, 244, 110, 252, 95, 156, 34,
            248, 195, 141],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 90
            }
          }
        },
        "3:46:embedded": {
          "1:0:bytes": [
            91, 22, 185, 64, 72, 46, 38, 48, 20, 244, 241, 114, 1, 64, 97, 227,
            136, 54, 169, 201, 133, 11, 182, 88, 154, 1, 142, 138, 24, 112,
            166, 16],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 168
            }
          }
        },
        "3:47:embedded": {
          "1:0:bytes": [
            27, 146, 39, 199, 46, 197, 241, 106, 223, 55, 129, 191, 176, 123,
            232, 151, 44, 180, 31, 142, 137, 201, 21, 52, 94, 201, 111, 170,
            169, 93, 55, 131],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 76
            }
          }
        },
        "3:48:embedded": {
          "1:0:bytes": [
            193, 124, 22, 3, 213, 34, 101, 149, 246, 22, 8, 15, 68, 75, 165,
            76, 38, 150, 247, 77, 2, 140, 154, 249, 2, 205, 73, 232, 130, 104,
            69, 159],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 66
            }
          }
        },
        "3:49:embedded": {
          "1:0:bytes": [
            5, 193, 68, 1, 180, 40, 46, 163, 192, 112, 174, 29, 81, 223, 190,
            244, 3, 142, 55, 211, 8, 2, 192, 194, 30, 20, 55, 42, 41, 68, 125,
            127],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 136
            }
          }
        },
        "3:50:embedded": {
          "1:0:bytes": [
            83, 24, 100, 126, 8, 186, 138, 33, 95, 127, 89, 36, 2, 106, 137,
            183, 242, 92, 104, 95, 122, 198, 162, 7, 255, 251, 123, 96, 225,
            149, 63, 111],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 29
            }
          }
        },
        "3:51:embedded": {
          "1:0:bytes": [
            194, 142, 59, 4, 54, 96, 70, 2, 123, 91, 9, 252, 170, 235, 182, 98,
            37, 143, 10, 210, 186, 173, 103, 165, 149, 47, 171, 59, 201, 209,
            250, 66],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 107
            }
          }
        },
        "3:52:embedded": {
          "1:0:bytes": [
            99, 76, 68, 203, 167, 245, 211, 142, 143, 66, 189, 190, 254, 178,
            37, 12, 61, 195, 104, 178, 165, 186, 113, 253, 215, 1, 169, 54,
            129, 175, 212, 70],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 35
            }
          }
        },
        "3:53:embedded": {
          "1:0:bytes": [
            92, 240, 11, 68, 247, 15, 103, 182, 210, 65, 243, 114, 153, 230,
            135, 241, 160, 60, 31, 140, 166, 85, 107, 163, 252, 119, 167, 35,
            195, 207, 141, 18],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 20
            }
          }
        },
        "3:54:embedded": {
          "1:0:bytes": [
            52, 163, 30, 105, 147, 104, 203, 234, 85, 78, 118, 91, 238, 243,
            81, 81, 183, 127, 166, 173, 2, 33, 111, 160, 93, 35, 4, 128, 97,
            231, 134, 223],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 40
            }
          }
        },
        "3:55:embedded": {
          "1:0:bytes": [
            15, 45, 48, 189, 170, 219, 22, 126, 243, 217, 200, 106, 165, 165,
            120, 108, 150, 111, 105, 150, 85, 8, 120, 155, 210, 148, 32, 198,
            145, 49, 115, 16],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 26
            }
          }
        },
        "3:56:embedded": {
          "1:0:bytes": [
            27, 250, 155, 159, 74, 227, 46, 27, 185, 4, 150, 8, 184, 21, 240,
            149, 45, 244, 81, 252, 85, 159, 50, 201, 247, 73, 42, 60, 127, 194,
            238, 197],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 36
            }
          }
        },
        "3:57:embedded": {
          "1:0:bytes": [
            108, 3, 162, 113, 54, 72, 115, 18, 228, 40, 151, 67, 169, 226, 153,
            58, 138, 252, 59, 67, 200, 53, 128, 160, 233, 148, 198, 100, 2,
            236, 64, 76],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 127
            }
          }
        },
        "3:58:embedded": {
          "1:0:bytes": [
            49, 49, 177, 65, 227, 61, 198, 32, 171, 82, 125, 100, 152, 38, 31,
            134, 206, 214, 41, 7, 221, 160, 238, 165, 79, 21, 214, 112, 178,
            61, 11, 9],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 118
            }
          }
        },
        "3:59:embedded": {
          "1:0:bytes": [
            20, 105, 162, 168, 235, 1, 24, 192, 39, 86, 5, 217, 99, 35, 205,
            139, 169, 93, 95, 58, 226, 208, 58, 100, 127, 228, 120, 31, 18, 41,
            125, 188],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 24
            }
          }
        },
        "3:60:embedded": {
          "1:0:bytes": [
            34, 182, 106, 248, 174, 109, 85, 82, 233, 185, 158, 189, 109, 180,
            122, 16, 147, 191, 174, 75, 237, 181, 28, 126, 154, 187, 117, 74,
            222, 183, 40, 42],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 140
            }
          }
        },
        "3:61:embedded": {
          "1:0:bytes": [
            26, 231, 159, 209, 255, 47, 66, 73, 25, 159, 150, 146, 159, 24,
            180, 147, 187, 127, 158, 136, 140, 26, 16, 163, 73, 22, 192, 248,
            72, 201, 123, 70],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 160
            }
          }
        },
        "3:62:embedded": {
          "1:0:bytes": [
            203, 229, 192, 110, 98, 83, 18, 72, 171, 75, 44, 16, 145, 234, 53,
            21, 92, 92, 252, 180, 147, 252, 134, 164, 131, 200, 84, 216, 173,
            57, 215, 64],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 65
            }
          }
        },
        "3:63:embedded": {
          "1:0:bytes": [
            27, 37, 29, 129, 135, 60, 21, 21, 130, 47, 246, 84, 230, 29, 106,
            8, 164, 126, 104, 33, 221, 10, 59, 198, 65, 59, 120, 175, 206,
            115, 159, 192],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 150
            }
          }
        },
        "3:64:embedded": {
          "1:0:bytes": [
            247, 70, 240, 58, 235, 170, 216, 77, 82, 133, 127, 229, 69, 233,
            41, 152, 29, 26, 140, 211, 60, 199, 111, 14, 228, 194, 135, 49,
            207, 62, 100, 88],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 3
            }
          }
        },
        "3:65:embedded": {
          "1:0:embedded": {
            "3:0:bytes": [
              240, 189, 141, 59, 178, 229, 21, 207, 150, 181, 18, 214, 123,
              229, 94, 213, 47, 55, 0, 35, 94, 176, 10, 239, 63, 91, 177, 203,
              181, 232]
          },
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 2
            }
          }
        }
      },
      "3:2:embedded": {
        "1:0:varint": 1,
        "2:1:embedded": {
          "1:0:bytes": [
            33, 255, 48, 173, 71, 120, 45, 62, 197, 131, 213, 202, 76, 94, 249,
            217, 35, 187, 218, 99, 4, 123, 252, 140, 225, 146, 188, 168, 168,
            162, 182, 43]
        },
        "3:2:embedded": {
          "1:0:bytes": [
            25, 141, 201, 30, 174, 20, 216, 191, 35, 48, 111, 202, 181, 109,
            38, 200, 22, 81, 86, 189, 190, 86, 13, 133, 64, 168, 191, 133, 34,
            39, 191, 224],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 3
            }
          }
        },
        "3:3:embedded": {
          "1:0:bytes": [
            71, 158, 85, 141, 109, 205, 49, 21, 217, 217, 209, 39, 252, 123,
            76, 99, 122, 134, 75, 8, 32, 224, 96, 181, 34, 239, 108, 110, 14,
            13, 46, 205],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 2
            }
          }
        }
      },
      "3:3:embedded": {
        "1:0:varint": 0,
        "2:1:embedded": {
          "1:0:bytes": [
            203, 190, 37, 85, 163, 233, 86, 189, 68, 5, 138, 164, 64, 165, 54,
            146, 237, 162, 128, 49, 148, 179, 51, 34, 217, 7, 38, 108, 182,
            197, 160, 179]
        }
      },
      "3:4:embedded": {
        "1:0:varint": 0,
        "2:1:embedded": {
          "1:0:bytes": [
            163, 159, 42, 53, 128, 115, 90, 161, 149, 19, 157, 15, 58, 113,
            122, 238, 204, 104, 91, 216, 78, 131, 30, 240, 110, 166, 106, 159,
            237, 125, 147, 82]
        },
        "3:2:embedded": {
          "1:0:bytes": [
            57, 32, 198, 203, 112, 159, 189, 236, 244, 113, 104, 205, 165,
            135, 237, 217, 163, 184, 202, 45, 241, 164, 164, 78, 112, 12, 177,
            124, 204, 213, 16, 78],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 3
            }
          }
        },
        "3:3:embedded": {
          "1:0:bytes": [
            220, 184, 103, 130, 108, 220, 83, 140, 36, 238, 139, 5, 167, 253,
            252, 136, 76, 43, 72, 36, 245, 92, 47, 147, 40, 134, 117, 179, 88,
            9, 164, 70],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 2
            }
          }
        }
      },
      "3:5:embedded": {
        "1:0:varint": 1,
        "2:1:embedded": {
          "1:0:bytes": [
            240, 142, 243, 236, 188, 6, 32, 37, 148, 220, 19, 135, 176, 7, 175,
            172, 234, 124, 152, 61, 115, 11, 68, 50, 219, 32, 182, 146, 2, 41,
            153, 192]
        },
        "3:2:embedded": {
          "1:0:bytes": [
            245, 12, 255, 55, 29, 151, 184, 242, 250, 247, 191, 244, 52, 251,
            172, 66, 40, 242, 47, 67, 168, 136, 224, 201, 229, 16, 64, 4, 36,
            207, 164, 97],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 3
            }
          }
        },
        "3:3:embedded": {
          "1:0:bytes": [
            98, 200, 36, 229, 239, 75, 96, 35, 195, 26, 180, 253, 4, 232, 178,
            167, 173, 163, 171, 110, 154, 60, 20, 229, 82, 52, 201, 194, 199,
            137, 188, 237],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 2
            }
          }
        }
      },
      "3:6:embedded": {
        "1:0:varint": 1,
        "2:1:embedded": {
          "1:0:bytes": [
            36, 1, 15, 223, 76, 25, 153, 9, 204, 90, 139, 114, 200, 122, 201,
            226, 179, 79, 135, 58, 82, 134, 136, 184, 34, 249, 131, 132, 127,
            38, 46, 245]
        },
        "3:2:embedded": {
          "1:0:bytes": [
            110, 242, 238, 199, 145, 159, 168, 178, 187, 136, 71, 7, 156, 155,
            102, 157, 218, 30, 147, 63, 91, 89, 147, 79, 29, 133, 10, 154, 77,
            107, 15, 23],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 3
            }
          }
        },
        "3:3:embedded": {
          "1:0:bytes": [
            193, 203, 71, 244, 30, 18, 158, 188, 15, 77, 73, 13, 22, 120, 82,
            107, 224, 130, 68, 135, 58, 123, 59, 135, 29, 86, 232, 139, 54, 74,
            77, 121],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 2
            }
          }
        }
      },
      "3:7:embedded": {
        "1:0:varint": 0,
        "2:1:embedded": {
          "1:0:embedded": {
            "2:0:varint": 495613890054,
            "192224:1:float32": 4.882061335059751e-12,
            "13:2:float64": -1.0035307849984653e+45,
            "14:3:float64": -9.42824039531738e+194
          }
        },
        "3:2:embedded": {
          "1:0:bytes": [
            176, 193, 111, 217, 103, 210, 40, 38, 174, 253, 210, 197, 138, 118,
            79, 56, 223, 186, 161, 214, 205, 215, 175, 9, 245, 199, 58, 188,
            87, 17, 112, 187],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 3
            }
          }
        },
        "3:3:embedded": {
          "1:0:bytes": [
            233, 74, 153, 41, 23, 225, 3, 244, 202, 119, 170, 143, 9, 6, 210,
            63, 125, 169, 131, 143, 182, 92, 221, 250, 202, 54, 145, 84, 30,
            120, 18, 91],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 2
            }
          }
        }
      },
      "3:8:embedded": {
        "1:0:varint": 1,
        "2:1:embedded": {
          "1:0:bytes": [
            168, 15, 228, 127, 125, 117, 127, 138, 147, 171, 112, 68, 159, 126,
            29, 136, 159, 179, 53, 127, 49, 203, 4, 114, 246, 31, 236, 30, 138,
            177, 114, 180]
        },
        "3:2:embedded": {
          "1:0:bytes": [
            175, 38, 148, 203, 5, 192, 218, 240, 99, 37, 193, 198, 171, 54,
            171, 189, 43, 21, 47, 93, 178, 90, 122, 26, 84, 147, 81, 211, 72,
            159, 117, 186],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 120
            }
          }
        },
        "3:3:embedded": {
          "1:0:bytes": [
            178, 168, 118, 168, 112, 230, 109, 168, 126, 135, 179, 184, 202,
            71, 168, 52, 173, 232, 47, 90, 206, 58, 2, 36, 231, 168, 28, 159,
            121, 169, 250, 225],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 160
            }
          }
        },
        "3:4:embedded": {
          "1:0:bytes": [
            27, 161, 172, 103, 148, 85, 34, 240, 54, 186, 19, 156, 128, 76,
            161, 194, 205, 44, 121, 156, 95, 221, 165, 157, 48, 84, 171, 94,
            213, 94, 38, 32],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 240
            }
          }
        },
        "3:5:embedded": {
          "1:0:bytes": [
            59, 22, 204, 77, 122, 25, 137, 251, 172, 27, 167, 105, 49, 28, 42,
            101, 237, 95, 111, 59, 71, 48, 155, 192, 72, 229, 119, 45, 87, 83,
            228, 126],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 320
            }
          }
        },
        "3:6:embedded": {
          "1:0:bytes": [
            8, 33, 151, 137, 172, 94, 16, 17, 78, 72, 18, 122, 33, 27, 94, 14,
            210, 96, 130, 155, 222, 163, 85, 72, 14, 65, 157, 51, 80, 239, 102,
            159],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 480
            }
          }
        },
        "3:7:embedded": {
          "1:0:bytes": [
            56, 238, 38, 244, 65, 33, 107, 152, 55, 119, 194, 4, 193, 171, 0,
            161, 170, 76, 178, 1, 83, 171, 68, 124, 231, 251, 16, 58, 69, 140,
            73, 27],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 640
            }
          }
        },
        "3:8:embedded": {
          "1:0:bytes": [
            234, 0, 220, 53, 6, 255, 39, 198, 77, 205, 185, 199, 74, 82, 77,
            238, 19, 189, 175, 169, 229, 243, 213, 98, 178, 88, 114, 237, 130,
            176, 18, 73],
          "2:1:embedded": {
            "1:0:embedded": {
              "1:0:varint": 213
            }
          }
        },
        "3:9:embedded": {
          "1:0:bytes": [
            185, 165, 104, 89, 84, 74, 209, 29, 242, 21, 183, 113, 130, 246,
            55, 41, 106, 125, 21, 102, 221, 45, 71, 190, 159, 70, 149, 140, 48,
            167, 19, 193],
          "2:1:embedded": {
            "5:0:embedded": {
              "1:0:varint": 40
            }
          }
        },
        "3:10:embedded": {
          "1:0:bytes": [
            220, 55, 196, 143, 179, 190, 76, 224, 62, 229, 56, 186, 142, 119,
            251, 254, 170, 172, 89, 23, 229, 85, 169, 193, 135, 234, 5, 63, 19,
            102, 182, 115],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 3
            }
          }
        },
        "3:11:embedded": {
          "1:0:bytes": [
            129, 101, 107, 114, 78, 83, 69, 51, 80, 76, 1, 218, 223, 168, 239,
            110, 132, 179, 104, 145, 7, 183, 83, 83, 248, 208, 228, 139, 134,
            120, 52, 26],
          "2:1:embedded": {
            "3:0:embedded": {
              "1:0:varint": 2
            }
          }
        }
      },
      "3:9:embedded": {
        "1:0:varint": 0,
        "2:1:embedded": {
          "1:0:bytes": [
            74, 175, 233, 99, 240, 93, 193, 197, 121, 201, 157, 138, 122, 204,
            35, 17, 29, 212, 57, 239, 239, 42, 0, 122, 150, 248, 198, 205, 34,
            3, 51, 162]
        }
      }
    }
  },
  "7:5:varint": 1,
  "8:6:varint": 2,
  "9:7:varint": 2
}

В данных изредка попадаются занятные строки: android.hardware.ram.low, com.samsung.feature.SAMSUNG_EXPERIENCE, com.google.android.apps.photos.PIXEL_2018_PRELOAD. Эти строки — не очень документированные имена функций, которые могут быть у устройства.


Описание функций, если они есть, можно посмотреть, на устройстве в файлах в папке /etc/sysconfig/:


adb shell cat /etc/sysconfig/pixel_experience_2017.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- These are configurations that should exist on Google's 2017 and newer Nexus devices. -->
<config>
    <!-- This is meant to be the canonical feature identifying 2017 and newer Nexus devices. -->
    <feature name="com.google.android.feature.PIXEL_2017_EXPERIENCE" />
</config>

adb shell cat /etc/sysconfig/pixel_2017_exclusive.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- These are configurations that should exist on Google's 2017 devices (and not newer/older) -->
<config>
    <!-- This defines the Photos preload feature for specifically the 2017 Pixel devices. -->
    <feature name="com.google.android.apps.photos.PIXEL_2017_PRELOAD" />
</config>

В качестве документированного примера можно привести проверку наличия камеры запросом функции android.hardware.camera через метод hasSystemFeature класса PackageManager. Но зачем нужны эти строки, в данном контексте непонятно.


Мне не удалось угадать, найти или восстановить схему данных из классов APK «Play Маркет». Если кто-то расскажет, что там и как получилось это определить, будет интересно. Пока есть только предположения разработчиков утилиты от Avast о структуре ProtoBuf и о том, что строка com.google.android.apps.photos.PIXEL_2018_PRELOAD указывает, является ли приложение системным/предустановленным:


1 <varint> = 1  // frosting versions?
2 <varint> = 0
3 <varint> = 1
4 <varint> = 1541545744578  // Timestamp of the frosting creation?
5 <chunk> = message:
    8 <chunk> = message:
        1 <chunk> = message(1 <varint> = 22)  // minSdkLevel?
        6 <varint> = 2
    9 <chunk> = message:
        1 <chunk> = message(1 <varint> = 2266, 4 <varint> = 2)  // versionCode
        2 <chunk> = message(1 <varint> = 50003, 4 <varint> = 4)
    10 <chunk> = message:
        1 <chunk> = bytes (30)  // ?? only last byte changes across apks
            0000   FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
            0010   FF FE FF FF FF FF FF FF FF FF FF FF FF 3F
            '.............................?'
        3 <chunk> = message:
            1 <chunk> = bytes (32)  // sha256 of something?
                0000   16 F8 22 A6 93 26 89 34 D8 2A 88 BB 8C AD B6 68
                0010   2C EB 77 A8 AA E4 5F AA F9 3C CA 63 44 2A A4 B9
                '.."..&.4.*.....h,.w..._..<.cD*..'
            2 <varint> = 20

Я бы хотел оставить несколько комментариев на этот счет.


1) По поводу строки com.google.android.apps.photos.PIXEL_2018_PRELOAD: легко доказать, что это неверное предположение. Скачаем несколько образов, предоставляемых Google, и увидим, что там нет не только таких строк, но и ни одного приложения, которое бы содержало блок Frosting.


Можно рассмотреть это более детально на образе walleye for Pixel 2 9.0.0 (PQ3A.190801.002, Aug 2019). Установим образ и обнаружим, что среди всех 187 APK-файлов нет ни одного файла, содержащего блок Frosting. Если обновить все приложения, блок Frosting обнаружится у 33 из 264 APK-файлов. При этом только у пяти из них присутствуют строки:


  • com.google.android.as:
    • com.google.android.feature.DPS
    • com.google.android.feature.PIXEL_EXPERIENCE
    • com.google.android.feature.PIXEL_2017_EXPERIENCE
    • com.google.android.feature.PIXEL_2019_EXPERIENCE
    • com.google.android.feature.ANDROID_ONE_EXPERIENCE
    • com.google.android.feature.PIXEL_2018_EXPERIENCE
    • com.google.android.feature.PIXEL_2020_EXPERIENCE
  • google.android.inputmethod.latin:
    • android.hardware.ram.low
  • google.android.dialer:
    • com.google.android.apps.dialer.GO_EXPERIENCE
    • com.google.android.feature.PIXEL_2020_EXPERIENCE
  • google.android.GoogleCamera:
    • android.hardware.camera.level.full
  • google.android.apps.photos:
    • com.google.android.feature.PIXEL_2020_EXPERIENCE

Можно предположить, что эти строки определяют необходимость функций на устройстве, куда устанавливается приложение. Но запросим полный список функций устройства, на котором проводилось обновление, и убедимся, что это не так.


Скрытый текст
adb shell pm list features

feature:reqGlEsVersion=0x30002
feature:android.hardware.audio.low_latency
feature:android.hardware.audio.output
feature:android.hardware.audio.pro
feature:android.hardware.bluetooth
feature:android.hardware.bluetooth_le
feature:android.hardware.camera
feature:android.hardware.camera.any
feature:android.hardware.camera.ar
feature:android.hardware.camera.autofocus
feature:android.hardware.camera.capability.manual_post_processing
feature:android.hardware.camera.capability.manual_sensor
feature:android.hardware.camera.capability.raw
feature:android.hardware.camera.flash
feature:android.hardware.camera.front
feature:android.hardware.camera.level.full
feature:android.hardware.faketouch
feature:android.hardware.fingerprint
feature:android.hardware.location
feature:android.hardware.location.gps
feature:android.hardware.location.network
feature:android.hardware.microphone
feature:android.hardware.nfc
feature:android.hardware.nfc.any
feature:android.hardware.nfc.hce
feature:android.hardware.nfc.hcef
feature:android.hardware.opengles.aep
feature:android.hardware.ram.normal
feature:android.hardware.screen.landscape
feature:android.hardware.screen.portrait
feature:android.hardware.sensor.accelerometer
feature:android.hardware.sensor.assist
feature:android.hardware.sensor.barometer
feature:android.hardware.sensor.compass
feature:android.hardware.sensor.gyroscope
feature:android.hardware.sensor.hifi_sensors
feature:android.hardware.sensor.light
feature:android.hardware.sensor.proximity
feature:android.hardware.sensor.stepcounter
feature:android.hardware.sensor.stepdetector
feature:android.hardware.telephony
feature:android.hardware.telephony.carrierlock
feature:android.hardware.telephony.cdma
feature:android.hardware.telephony.euicc
feature:android.hardware.telephony.gsm
feature:android.hardware.touchscreen
feature:android.hardware.touchscreen.multitouch
feature:android.hardware.touchscreen.multitouch.distinct
feature:android.hardware.touchscreen.multitouch.jazzhand
feature:android.hardware.usb.accessory
feature:android.hardware.usb.host
feature:android.hardware.vr.headtracking
feature:android.hardware.vr.high_performance
feature:android.hardware.vulkan.compute
feature:android.hardware.vulkan.level
feature:android.hardware.vulkan.version=4198400
feature:android.hardware.wifi
feature:android.hardware.wifi.aware
feature:android.hardware.wifi.direct
feature:android.hardware.wifi.passpoint
feature:android.hardware.wifi.rtt
feature:android.software.activities_on_secondary_displays
feature:android.software.app_widgets
feature:android.software.autofill
feature:android.software.backup
feature:android.software.cant_save_state
feature:android.software.companion_device_setup
feature:android.software.connectionservice
feature:android.software.cts
feature:android.software.device_admin
feature:android.software.device_id_attestation
feature:android.software.file_based_encryption
feature:android.software.home_screen
feature:android.software.input_methods
feature:android.software.live_wallpaper
feature:android.software.managed_users
feature:android.software.midi
feature:android.software.picture_in_picture
feature:android.software.print
feature:android.software.securely_removes_users
feature:android.software.sip
feature:android.software.sip.voip
feature:android.software.verified_boot
feature:android.software.voice_recognizers
feature:android.software.vr.mode
feature:android.software.webview
feature:com.google.android.apps.dialer.SUPPORTED
feature:com.google.android.apps.photos.PIXEL_2017_PRELOAD
feature:com.google.android.feature.EXCHANGE_6_2
feature:com.google.android.feature.GOOGLE_BUILD
feature:com.google.android.feature.GOOGLE_EXPERIENCE
feature:com.google.android.feature.PIXEL_2017_EXPERIENCE
feature:com.google.android.feature.PIXEL_EXPERIENCE
feature:com.google.android.feature.TURBO_PRELOAD
feature:com.google.android.feature.WELLBEING
feature:com.google.android.feature.ZERO_TOUCH
feature:com.google.hardware.camera.easel
feature:com.verizon.hardware.telephony.ehrpd
feature:com.verizon.hardware.telephony.lte

2) С frosting versions я не согласен, так как можно найти похожие данные, но со значениями, отличными от 1. Максимальное значение этого поля, которое мне попадалось, –– 26.


3) С timestamp of the frosting creation я не согласен: я понаблюдал за конкретным приложением и заметил, что с выходом новых версий значение этого поля не обязательно растет. Оно скачет и может быть отрицательным.


4) MinSdkLevel и VersionCode выглядят правдоподобно.


Заключение


Итак, блок Frosting в подписи помогает однозначно определить, распространялся ли файл через официальный магазин. Больше никакой пользы из этой подписи извлечь не удалось.


Ловите напоследок пример использования такой информации в отчете мобильной песочницы ApkLab:


Tags:
Hubs:
+13
Comments 4
Comments Comments 4

Articles

Information

Website
bi.zone
Registered
Employees
501–1,000 employees
Location
Россия