SReverseby Simpa Labs

Capabilities · Request signing

You can see the request.
You can't recreate its signature.

The app builds a signature for every call. Copying a request copies one signature from one moment. A working reproduction computes a fresh signature for the moment you send.

HMAC ECDSA X-Signature X-Timestamp X-Nonce
captured · headers
POST /v2/account HTTP/2
X-Timestamp: 1738307384
X-Nonce: 6c1b9e7f2a3d41c0
X-Signature: 3b2e...b91a

{"account":"ABC123"}

Where signing lives

Find the code that signs, then read what it signs.

  • OkHttp / Retrofit interceptor
  • A custom Interceptor wrapping every call
  • Native code behind a JNI method
  • A token fetched from the server before the call
  • A signing service bound to the device
  • An embedded key the app decrypts at runtime
  • A signature computed over a canonical string
  • A per-call value the app generates fresh
Interceptor

Signed requests often pass through one code path. Find the Interceptor and the signing call is usually one hop away.

Native

If the signer is a JNI method, the algorithm lives in a .so and moves into disassembly.

Where the key sits

The key may be static, derived, or fetched. Each changes how you reproduce it.

The signed input

What the app folds into one value

The signature is the result of a function. Rebuilding it means knowing both the function and the exact bytes it takes in.

MethodPOST, GET Path/v2/account Bodynormalized JSON Timestampseconds since epoch Nonceunique per call Keystatic / derived / fetched

A canonical string is a fixed order of those parts. If you get the order wrong, the signature does not match even when you use the right key.

The algorithm

HMAC or ECDSA. Each changes the work.

HMAC / SHA-256

One shared secret

The app and the server keep the same key. Reproduce the digest and you reproduce the signature. The key and the canonical order are the whole problem.

ECDSA / key pair

A private key signs

The server only has the public half. Reproducing the signature requires the private key the app holds, which makes key recovery the deciding question.

How we read it

Trace the call to the signer

01

Inspect the dex

Disassemble the application and locate the request path and the interceptor that attaches the signature.

02

Read the canonical string

Reconstruct the exact order and encoding of method, path, body, timestamp and nonce.

03

Follow into native

If the signer is a JNI method, open the .so in a disassembler and map the native flow back to the request.

04

Recover the key

Find the key, or the derivation that produces it, so the signature can be produced outside the app.

The point

The signature is a function of the request and a key. Recreate the function and the request stops being a replay.

Reproduce it

Sign the request the same way

signature.py
# rebuild the signature, not replay it
import hashlib, hmac, time, secrets, requests

KEY = bytes.fromhex("9f2c...")

def sign(method, path, body, ts, nonce):
    text = "\n".join([method, path, body, ts, nonce])
    return hmac.new(KEY, text.encode(), hashlib.sha256).hexdigest()

ts = str(int(time.time()))
nonce = secrets.token_hex(8)
body = '{"account":"ABC123"}'

requests.post(
    base + "/v2/account",
    data=body,
    headers={"X-Timestamp": ts,
             "X-Nonce": nonce,
             "X-Signature": sign("POST", "/v2/account", body, ts, nonce)},
)

Fig. 01 · the same function the app runs, outside the app

pre-request script
// runs before every request in the collection
const ts = Math.floor(Date.now() / 1000).toString();
const nonce = CryptoJS.lib.WordArray.random(8).toString();
const text = ["POST", "/v2/account", pm.variables.get("body"), ts, nonce].join("\n");
pm.variables.set("ts", ts);
pm.variables.set("nonce", nonce);
pm.variables.set("signature", CryptoJS.HmacSHA256(text, KEY).toString());

Fig. 02 · the same signature regenerated per request in Postman

Send us the app

Need the request to be accepted?

We read the signing code off the application and hand you a working signature in Python, TypeScript or Postman.

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

One full APK. One complete delivery.

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

Every format included

Python, JavaScript/TypeScript, Postman and complete API documentation cover the same full endpoint set. Your team runs the clients in its own server or system.

Ready in 24–72 hours

The delivery window starts after we receive the APK and any account access needed to run it. The fixed quote states the deadline. Most projects finish sooner.

Deployment checked before the quote

The package includes signing, encryption, decryption and session handling. We verify device-bound keys and server integrity checks during review and document runtime requirements before you commit.

30 days of fixes

Report a defect within 30 days of delivery. We fix any delivered call that does not match the tested APK at no extra cost.

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?