← Back to Writeups
CUSTOMMediumReversing

Квиз (Quiz)

XESXOR9/2/20262 min read
#reversing#custom#medium#bytecode_reverse_engineering#custom_disassembler_developmen#hermes_v96_disassembly#jwt_api_interaction#sha256_hash_chain_reconstructi#string_table_extraction

Квиз (Quiz)

Platform: duckerz | Category: Reversing | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-02-11 | Status: Solved Techniques: bytecode_reverse_engineering, custom_disassembler_development, hermes_v96_disassembly, jwt_api_interaction, sha256_hash_chain_reconstruction, string_table_extraction

Summary

Task: React Native APK with Hermes v96 bytecode containing hidden token generation logic. Solution: Custom disassembler to extract string table, reconstruct 5-step SHA256 hash chain algorithm, generate final token for API flag retrieval.

Квиз (Quiz) — DUCKERZ CTF

Description

Хотим выкатить с друзьями безобидное приложение, повышающее кругозор. Мне пообещали, что никаких секретов там нет.

One file provided:

  • quiz.apk (~83MB) — Android APK, React Native (Expo) application with Hermes JavaScript bytecode

Category: Reverse Engineering Points: 300 | Difficulty: Medium

Analysis

Step 1: Initial Reconnaissance

The APK is a React Native (Expo) application. The JavaScript bundle is compiled into Hermes bytecode version 96 — this is not regular JS, but a binary format for Meta's Hermes virtual machine. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Standard tools (hbctool) do not support Hermes v96, so a fully custom approach was required.

Step 2: Extracting Strings from Hermes Bytecode

From 16,005 strings in the string table, key ones were found:

  • API endpoints: /api/riddle/next, /api/riddle/answer, /get_flag
  • Functions: activateStep1-activateStep5, generateFinalToken, isFlagReady, generateHash, createToken
  • Suffixes: _activated, _final, _secure
  • 11 hex strings (salts): a7f3e9c2b8d4f1a6, 9e2c8b5f3a7d1e4c, ... ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 3: Custom Hermes v96 Disassembler

A disassembler was written from scratch (~192 opcodes), parsing 14,681 functions. Targeted analysis of key token generation functions.

Step 4: Algorithm Reconstruction

5-step SHA256 hash chain with salts, double hashing for the final token.

Solution

python
#!/usr/bin/env python3
import hashlib

def sha256(s: str) -> str:
    return hashlib.sha256(s.encode()).hexdigest()

salts = [
    "a7f3e9c2b8d4f1a6",
    "9e2c8b5f3a7d1e4c",
    "6f8a2e5c9b3d7f1a",
    "4c9e7a2f5b8d1e3c",
    "2f6a9c5e8b1d4f7a",
]
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

step1 = sha256(salts[0] + "_activated")
step2 = sha256(salts[1] + "_" + step1)
step3 = sha256(salts[2] + "_" + step2)
step4 = sha256(salts[3] + "_" + step3)
step5 = sha256(salts[4] + "_" + step4)

combined = f"{step1}_{step2}_{step3}_{step4}_{step5}_final"
hash1 = sha256(combined)
final_token = sha256(hash1 + "_secure")
# -> 02833cfe8924def0704a474fbb5f56c6510be338c94b38c7def44155e8f0ae1b

POST /get_flag with the token and JWT authorization -> flag. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍