SReverseby Simpa Labs

Encryption & Encoding

Reverse engineering encrypted Android request bodies

An encrypted body is not an encoded one. The cipher and the key source decide how you reproduce it.

Name the transformation before you trace it

An opaque request body can be encrypted, compressed, serialized or Base64-wrapped, and those are different problems. Confusing them wastes time, so decide which one you are looking at first. The content type, the magic bytes, the change in length and the code that creates the body tell you.

SignalWhat it usually isNext check
Body starts with 1f 8b 08GzipDecompress, then inspect the inner bytes.
Body is a short set of printable charactersBase64Decode, then check the structure.
Body is tagged binary with field boundariesProtobuf or a custom serializerMap fields, not cipher. It is structured data, not a secret.
No readable header, length shifts with inputA cipherFind the mode, key source, IV and authentication tag.

Follow the bytes backward

Begin where the body enters the HTTP client and trace its inputs. The function that returns those bytes is the last place you need to read; work from it back to the plain object. That exposes the serializer, the compression step, the cipher mode, the key source, the IV or nonce and the final encoding. Order matters: JSON that is compressed then encrypted produces different bytes from JSON encrypted then compressed.

# compare your reconstruction with the app output, byte for byte
python3 -c 'import sys,binascii; d=sys.stdin.buffer.read(); print(len(d), binascii.hexlify(d[:16]).decode())'
# 7b 22 ...  -> starts with { "   plaintext JSON
# 1f 8b 08   -> gzip
# edef / 08  -> ciphertext or protobuf, not a text envelope

Constants in Java or Kotlin are only one source. A key or a salt can come from remote configuration, the Android Keystore, a native library or an earlier handshake. A native method that returns a byte array needs the same input-and-output tracing as a Java method, because that is often where the key or the derived value is created.

Reproduce exact bytes

  • Preserve field order when signing or encryption uses the raw serialized bytes.
  • Match character encoding, padding and newline rules.
  • Track whether timestamps are seconds, milliseconds or formatted text.
  • Confirm whether the IV is random, derived or sent beside the ciphertext.
  • Keep binary data as bytes until the protocol explicitly encodes it.

The signer is rarely given a JSON object. It is given a byte array, so the reconstruction has to produce that byte array exactly. Reformatting the JSON, reordering keys or letting a serialiser add a space will change the signature even though the parsed object is identical.

Test with controlled inputs

Change one field in the app and compare the output. Repeated plaintext producing repeated ciphertext points to deterministic inputs. A different ciphertext on every run points to a fresh IV, nonce or session value. Confirm at the function boundary by logging the arguments and the return of the serialiser and the cipher, so you know which step produced what you are looking at.

A worked example

Say the app encrypts a body with AES-256-GCM and sends the IV and the tag beside the ciphertext as Base64 fields. The client must derive the same key, generate a fresh IV for each call, encrypt the exact serialised JSON, base64-encode the IV, the ciphertext and the tag and package them in the order the server expects. A fixed IV copied from the app looks correct, but the authentication tag will not validate on a second call because GCM binds the tag to the ciphertext and the IV.

The final client should accept normal business inputs and perform the full transformation itself. A pasted encrypted blob proves little, because it cannot generate the next valid request.

Some servers also reject a ciphertext or a nonce they have seen before, so a request that is correct can still fail if you reuse an old value. That is a per-call rule, not an algorithm error, and the client has to generate a fresh value each time it runs.

Keep a log of the order each step runs: plain object, serializer, compression, cipher, encoding. When you change one field and the output changes in a way you did not expect, the log tells you which step consumed that field and which one did not. That is usually faster than re-deriving the whole pipeline from scratch.

Reviewed 30 August 2026 · SReverse research desk

Related

Relevant capability

Python API client

Start a project

Send the full APK

Send the full APK. We review the application and quote its complete API reconstruction.

Projects start at $120. Most are delivered in 24 to 72 hours.

Start your full APK reconstruction

Send the full APK

Projects start at $120. Choose WhatsApp or email, then attach the APK in the app that opens. We reply within one hour with the next step and send the fixed quote after review.

Want us to contact you?