Reverse Engineering Mobile Apps with JADX and Hopper
Read this first: Legal and ethical preface
When you reverse engineer mobile apps, you can find out private user data, credentials, and proprietary logic. You should only do reverse engineering if you have clear permission, such as a written agreement, a bug-bounty program scope, your own apps, or a formal pentest agreement. Do not try to get to data or systems that you are not allowed to test. If you find secrets or weaknesses, follow coordinated disclosure: tell the vendor, give them steps to reproduce the problem, and don't publish live secrets.
What are JADX and Hopper, and when should you use them?
JADX is an open-source Android decompiler that turns APK (DEX) bytecode into Java-like source code that you can read. Great for quickly looking at the structure of an app, including its packages, classes, methods, resources, and manifest. Quick, with both a graphical user interface (GUI) and a command line interface (CLI), this is great for static analysis that focuses on Android.
Hopper is a commercial disassembler and decompiler for macOS and Linux that is usually used for native binaries (ARM/ARM64/x86). It can help you look at .so files (native libraries) in Android APKs or iOS/macOS binaries, understand low-level control flow, and look at compiler artifacts.
When you look at a mobile app, you'll often use both:
Use JADX first for layouts, high-level Java/Kotlin logic, and the manifest.
If you have native libraries (lib*.so) or if JADX's decompilation isn't complete (obfuscated methods compiled to native code), or if you have iOS Mach-O binaries, use Hopper.
Set up a safe lab (this is the first step)
Use a network segment that is watched or an isolated network (no internet).
Use virtual machines or containers that you can throw away or that have snapshots.
Use physical test devices or emulators that are set up for testing (rooted/emulator with debugging turned on). Do not use real data.
Make copies of the original APK/IPA and work with those.
Keep records of results and a documented chain of custody (this is useful for reports).
High-level workflow (reverse engineering in an ethical way)
Check the scope and the authorization. Check that the targets and methods are allowed.
Get artifacts. Get APK/IPA from a trusted source, like a developer build, the Play Store APK through approved methods, or the client.
Static inspection: resources and manifest. Look for permissions, hardcoded URLs, exported components, and resources that are built in.
JADX can decompile Java and Kotlin. Look into the package structure, entry points, and business logic.
Check out native libs (Hopper). Look at exported functions, cryptographic calls, and JNI bridges.
Look for patterns that aren't safe. Hardcoded keys, weak encryption, random numbers that aren't safe, HTTP that isn't safe, debug flags, and bad logging.
Write it down and check it. If a possible problem is found, check it in a controlled dynamic environment (emulator/device) only if it's within the scope.
Report in a responsible way. Include steps to reproduce the problem (but not any stolen secrets), the effect, and suggested fixes.
What to look for and how to read the results when using JADX
What you get with JADX
Decompiled Java/Kotlin sources (roughly; not 1:1).
Class and method names that aren't too hard to read.
AndroidManifest.xml, resource files, and built-in assets.
Figuring out what decompiled output means
It is possible to read decompiled code, but it may have fake variable names (like var1, a, and b) if it has been obfuscated. Instead of identifiers, pay more attention to logic and how to use APIs.
Look for entry points like Application subclass, Activity onCreate, Service onStartCommand, broadcast receivers, and ContentProviders.
IPC includes things like Binder, AIDL, exported components, and sockets/listeners.
Patterns to look for (examples of insecure patterns—find, don't use)
Hardcoded secrets are things like passwords, API keys, tokens, or asymmetric keys that are stored as constants or in resources. An example of an unsafe pattern is
// insecure pattern (don't take out or publish real keys)
private static final String API_KEY = "REDACTED";
If you see these kinds of patterns in your authorized audit, write down where they are and suggest safe storage (KeyStore / KeystoreManager, server-side storage).
Bad crypto use: using old algorithms like MD5 and SHA-1 for signatures, ECB mode for AES, or hardcoded IVs and nonces. Example of an insecure structure:
Cipher.getInstance("AES/ECB/PKCS5Padding")
Suggest using authenticated encryption (AES-GCM), making sure the IV is generated correctly, and managing keys.
Insecure randomness: using new Random() to make tokens is not safe. Use SecureRandom instead.
Not properly pinning certificates or turning off validation, like using a custom X509TrustManager that accepts all certs. Mark as important.
Debuggable builds: android:debuggable="true" or debug flags and logs are present.
Sensitive data logging: logging tokens, PII to Log.d/System.out.
Unsafe storage: putting secrets in SharedPreferences without encrypting them or writing sensitive files to places where anyone can read them.
Using Hopper for native analysis (what to look at)
Why being native is important
Native may have sensitive logic, crypto implementations, or checks to make sure things don't get messed up. so files.
JNI bridges often send sensitive data back and forth between Java and native layers.
Hopper analysis workflow (in theory)
Hopper helps with this by loading the binary and setting the right architecture (ARM/ARM64/x86).
Check out exported symbols and named functions. Look for functions that are likely to be related to cryptography or networking.
Use the call graph to see how data goes to and from native functions.
Check out string tables. Strings that are part of native code can show URLs, commands, or keys (again, only list what you find for authorized testing).
Find compiler intrinsics and anti-debugging tools. These can show that the code is tamper-resistant, which can change how you test it.
What to look for as a security reviewer
Custom crypto routines that reimplement standard primitives (which are often buggy). Suggest libraries that have been checked out (BoringSSL/OpenSSL or platform crypto).
Native functions that seem to let Java see secrets through JNI without any security. Advise limiting JNI exposure and using platform KeyStore.
Helpful tips for practical analysis (ethical and focused on defense)
Not just names, but also how you use APIs. It's better to look for calls to Cipher, KeyStore, getSharedPreferences, Log, HttpURLConnection, OkHttpClient, and CertificatePinner than method names.
Track data flows by starting at the input points (like network responses and intents) and going all the way to storage or output. This helps you find out where sensitive data is stored or logged.
Use obfuscation as a sign: a lot of obfuscation usually means that business logic is protected, but it can also hide unsafe practices. Obfuscation is not a way to make a design more secure.
Look for fallback behavior, which is code that either disables pinning or goes back to insecure checks if it fails (like in exception handlers).
Use automated scanners sparingly: tools can find low-hanging fruit (leaky logs, insecure permissions), but manual review is essential for context.
Example: finding unsafe use of crypto (safe, helpful)
Here are some small, safe examples that show the difference between insecure and secure patterns. These are helpful for training and making suggestions for fixing problems.
Don't use this pattern if you're insecure:
// not safe: RNG that is easy to guess and a weak cipher mode
Random r = new Random(); byte[] key = new byte[16]; r.nextBytes(key);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
More good:
// safe: use AES-GCM and SecureRandom
SecureRandom sr = new SecureRandom(); byte[] key = new byte[32]; sr.nextBytes(key);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
Use the right IV/nonce for each encryption.
If you see the insecure pattern in an authorized review, tell them where it is and suggest a safer option.
How to write a good vulnerability report for reporting findings
Summary: A brief description and how bad it is.
Impact: What an attacker could do if this problem exists (don't publish secrets that have been taken).
Proof: file names, class/method names, and line numbers (a screenshot or code snippet that doesn't show any live secrets). For instance, in com.example.network.ApiClient.java, the sendCredentials() method uses HttpURLConnection without enforcing TLS.
Steps to reproduce: Only include steps that are relevant and don't give away any secrets. For example, how to make a token log if you are testing on a provided build.
Fixes: Use Keystore, get rid of hardcoded secrets, use AES-GCM, make sure certificates are valid, and use application attestation when it's needed.
A suggested timeline for fixes and checking them again.
What developers should do to lessen the effects
Don't ever hardcode secrets into code or resources. Use a secure server-side storage system or a platform KeyStore/Keychain.
When it's appropriate, use platform TLS with the right certificate validation and certificate pinning. Don't turn off validation in fallback handlers.
Use libraries for cryptography that have been tested well. Use authenticated encryption (AES-GCM) whenever possible.
Keep as little sensitive data on the device as possible. Store data in a safe, encrypted place and delete it when you don't need it.
Don't write long logs in release builds, and don't keep personal information in diagnostic logs.
Use code and secrets scanning in CI (like pre-commit hooks and scanning tools) to find accidental commits.
Use runtime protections like safety checks, integrity verification, and attestation frameworks to stop tampering. But keep in mind that these are defenses, not substitutes for good key management.
Tools and resources for defenders and researchers
JADX is an open source decompiler that turns Android DEX files into Java files. Quickly check APKs with this.
Hopper is a disassembler and decompiler for native binaries on macOS and Linux. Good for looking at .so and Mach-O files.
Examples of static analysis tools include linting, secrets scanning (to stop commits), and SAST tools for Android.
Android KeyStore and iOS Keychain are two examples of platform docs. Read the official documents to learn how to use them safely.
Use vendor policy, bug bounty programs, or the CVE process if they are appropriate for responsible disclosure frameworks.
(Important: I didn't include direct links or command examples in this article to avoid giving out instructions that could be misused.) If you are doing an authorized penetration test or working on your own app and want to learn by doing, I can make a targeted, limited-scope lab walkthrough that focuses only on defensive testing and fixing problems, with clear written permission details and safe examples.
A quick list of things to do for a mobile security review that has been approved
Verify the written permission and scope.
Look in AndroidManifest.xml for exported parts and permissions.
Look for Cipher, KeyStore, SecureRandom, Log, and SharedPreferences in decompiled Java/Kotlin.
Look through resources and assets for secrets.
Look at native. so files for JNI bridges and strings.
Find HTTP endpoints that are not secure or that don't enforce TLS.
In release builds, look for debug flags and verbose logging.
Suggest fixes and check them in a build that has been patched.
Last notes
When used correctly, reverse engineering is a powerful way to test and strengthen security. It shows developers risky patterns that attackers can use before they do. I can do the following next if you want:
Make a safe, hands-on lab guide that shows how to use JADX and Hopper on a sample app that you give them that is intentionally weak (or a canonical test app), and make sure to include language that makes it clear that they have permission to do so. OR
Make a short checklist or report template that you can use again for audits and pentests.
Let me know which of those you want (a lab guide for a test app or a report/checklist template), and I'll make it with strict ethical rules.
Comments
Post a Comment