SReverseby Simpa Labs

Flutter

Finding API logic inside a Flutter APK

Flutter apps still make plain HTTP requests. The Dart is compiled, so you observe the flow instead.

Find where the Dart logic lives

Release Flutter compiles Dart ahead of time into a snapshot inside libapp.so. The Android wrapper is mostly startup, manifests and platform channels; the request code is in the snapshot. Confirm the AOT build and locate the library, then pull strings from it. The strings give you the endpoints and the client library, and they do not give you the code that fills the headers or signs the body.

unzip -l app.apk | grep -E 'lib/.*/lib(app|flutter).so'
strings lib/arm64-v8a/libapp.so | grep -iE 'https?://|/api/v[0-9]' | sort -u
strings lib/arm64-v8a/libapp.so | grep -iE 'dio|http|graphql|protobuf' | sort -u

Use the client name to narrow the search. If the strings show dio, the request goes through a Dio client and its interceptors. If they show a GraphQL package, the request is a query or a mutation, and the app may use persisted-query hashes instead of full query text. If they show protobuf, the body is structured binary, which can look encrypted when it is not.

Reconstruct the snapshot, or trace the call

Two routes. To read Dart-level structure, reconstruct the snapshot from libapp.so with a Dart snapshot tool such as Blutter, which recovers classes, methods and fields from the AOT image. Names may be reduced if the app was built with code obfuscation, so verify by the value rather than the label. To observe the request directly, hook the runtime client or capture the traffic.

The snapshot route gives you the shape of the code. The hook and capture route gives you the actual bytes. You usually want both, because the shape tells you where the value is created and the bytes tell you what it is.

The interception gotcha

Flutter's built-in dart:io HttpClient uses its own certificate store and does not automatically trust a system proxy CA. Adding a system CA is often not enough, so a proxy that works for a native app can silently fail for a Flutter one. You either add your CA inside the app, hook the client to trust it, or patch the transport. A proxy set at the OS also does not always reach the Dart layer, so confirm the request actually leaves through the proxy before concluding the app is not calling the endpoint.

Platform channels move the hard step

A Dart call can cross a platform channel into Java, Kotlin, C or C++ for device checks, key access or signing. Follow any channel method used before the request. That is often where the value you cannot reproduce in Dart is created, and it is the reason a captured body replayed from Python fails.

# list the channel names referenced in the snapshot
strings lib/arm64-v8a/libapp.so | grep -iE 'channel|methodchannel|platform' | sort -u

Common reasons a replay fails

ObservationLikely causeWhere to look
Headers differ from the code you seeA Dio interceptor adds headers after Dart builds the request.The Dio interceptor queue.
A call fails after a token errorA refresh interceptor retries with a new access token.The refresh interceptor and the refresh response.
A value is not in DartA native plugin supplies a device or crypto value.The platform channel and the native method.
The proxy sees no trafficCertificate pinning or a non-standard trust store.The transport or the client's certificate handling.
The body looks encryptedProtobuf or another binary serializer.Field boundaries, not cipher.

Confirm what the app actually sent

Capture at the network boundary with your CA injected inside the app, then compare the request to the strings and the reconstructed snapshot. The endpoint and the client library are in the snapshot; the headers and body are what the app produced at send time. When the two disagree, the interceptor or the platform channel is where the difference is.

A Dart method is not a Java method. Java.use-style hooks reach the wrapper and the platform channel, not the Dart code, which runs in the AOT snapshot. For the Dart layer you either reconstruct the snapshot or instrument the transport, and the two give different views of the same call.

Then rebuild the call in your target language from the captured bytes and the reconstructed generation rules. The server does not care that the app was written in Dart; it cares that the request is valid.

Reviewed 30 August 2026 · SReverse research desk

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?