Rebuilding request signing as a Burp extension, automatically
Proxying a modern mobile app is easy. Editing a request and having the server still accept it is where a day disappears. That part is mechanical enough to automate.
A tester's first hour with a banking app is usually spent on plumbing. Install the certificate, defeat the pinning, get traffic through the proxy. Then comes the real wall: the app signs each request, the proxy edits the body, the signature no longer matches, and every response is a 401. Nothing about the application logic has been tested yet.
The work from there is known and dull. Find the signing routine. Work out which bytes go into the message and in what order. Find the key, which is sometimes in a string table, sometimes assembled at runtime, sometimes XOR-ed in a native library. Reimplement it in Java or Python. Wrap it in a proxy extension. Discover you got the timestamp granularity wrong. Try again.
Why this is a good automation target
It is tedious, it is highly patterned, and, crucially, it has an oracle. You know immediately whether your reimplementation is right, because the server either accepts the request or it does not. That makes it very different from judging whether a finding is exploitable, where the feedback loop runs through a human.
So the agents do the recovery and then write the extension. The native-lib agent lifts the signing function, recovers the message construction and the key material, and emits a Burp extension that registers an HTTP listener and re-signs every request the proxy modifies. The result is a JAR you load into Burp, and Repeater works again.
In the sample app the routine concatenates a timestamp, a newline and the SHA-256 of the body, HMACs it with a key XOR-decoded in libcrypto_wrap.so, and sends the result as X-Acme-Sig alongside X-Acme-Ts. Reading that out of lifted ARM64 took the agent a few minutes. Writing it out as code took seconds. A person doing the same thing carefully would lose a morning.
Verification is not optional
Generated code that handles cryptography deserves suspicion, so the extension is not trusted because it compiles. Before it is shipped, the agent replays captured traffic through it and compares its signatures against the ones the app produced for the same inputs. Where a device or emulator is available, it sends a modified request and checks the server accepts it. If either check fails, the extension is not offered, and the finding about the signing scheme drops to Likely.
The source ships inside the JAR. That is deliberate: a tester should be able to read what a tool in their proxy is doing, and the most common edits, such as a different header name or an extra field in the message, take a minute once the structure is visible.
What it does not do
It does not break cryptography. If the key is derived from a server-issued secret, held in a hardware-backed keystore, or bound to device attestation, there is nothing in the binary to recover, and the agent says so. That is itself a useful result: it tells you the signing scheme is doing its job, and that the next hour is better spent elsewhere.
It also does not decide what to test. The extension removes an obstacle; it does not replace the judgement about which requests are interesting. That remains the tester's job, and we think it should.