Files
2026-09-17 00:50:07 +03:00

2.9 KiB

WasmCoat

Reverse medium

Android-клиент склада проверяет штрихкоды через WebAssembly. В раздатке есть WasmCoatScanner.apk, в котором нужно найти защитную конфигурацию. Ключ и данные разнесены между DEX и wasm, поэтому смотрим оба файла.

Решение

Из APK достаём classes.dex и assets/guard.wasm. В DEX-коде загрузчика находим строку wasmcoat-warehouse, которая используется как ключ.

Wasm начинается стандартной сигнатурой \0asm\x01\0\0\0. Дальше идёт последовательность секций:

id: u8 | размер: ULEB128 | содержимое секции

Нужны кастомные секции с id = 0. Внутри каждой сначала записаны длина имени в ULEB128 и само UTF-8-имя. Находим wasmcoat.guard и берём байты после её имени.

Размеры секций закодированы числами ULEB128, которые могут занимать разное количество байт. Если прочитать ULEB128 как обычный u32, границы секций съедут ещё до расшифровки.

Полезная нагрузка секции скрыта повторяющимся XOR:

import json
import zipfile

with zipfile.ZipFile("public/WasmCoatScanner.apk") as apk:
    wasm = apk.read("assets/guard.wasm")

def uleb(data, pos):
    value = shift = 0
    while True:
        byte = data[pos]
        pos += 1
        value |= (byte & 0x7f) << shift
        if not byte & 0x80:
            return value, pos
        shift += 7

assert wasm[:8] == b"\0asm\x01\0\0\0"
pos = 8
while pos < len(wasm):
    section_id = wasm[pos]
    size, pos = uleb(wasm, pos + 1)
    end = pos + size
    if section_id == 0:
        name_size, pos = uleb(wasm, pos)
        name = wasm[pos:pos + name_size].decode()
        if name == "wasmcoat.guard":
            blob = wasm[pos + name_size:end]
            break
    pos = end
else:
    raise ValueError("wasmcoat.guard не найдена")

key = b"wasmcoat-warehouse"
plain = bytes(b ^ key[i % len(key)] for i, b in enumerate(blob))
config = json.loads(plain)
print(config["target"])

С правильной границей секции получаем JSON. Значение target — искомый флаг. Запуск WebAssembly для его извлечения не нужен.

Солвер.

Флаг

caplag{android_wasm_guard_table_unwrapped}