Documentation Index Fetch the complete documentation index at: https://mintlify.com/HackTricks-wiki/hacktricks/llms.txt
Use this file to discover all available pages before exploring further.
Sometimes you need to modify an application’s code to access hidden information, bypass checks, or understand obfuscated logic. This page covers the complete workflow: decompile → modify → recompile → sign.
APK Decompilers
jadx The recommended choice. Decompiles DEX to readable Java. jadx app.apk # CLI decompilation
jadx app.apk -d ./output --no-res # No resources
jadx-gui # Launch GUI
JD-Gui Pioneering GUI Java decompiler. Open the APK directly in JD-Gui to inspect code.
Bytecode-Viewer Analyze using multiple decompilers simultaneously for cross-verification.
GDA Windows-only with extensive Android reverse engineering features.
CFR Handles modern Java features well. java -jar ./cfr.jar "app.jar" --outputdir "output/"
java -Xmx4G -jar ./cfr.jar "app.jar" --outputdir "output/"
frida-DEXdump Dumps the DEX of a running APK from memory — bypasses static obfuscation removed at runtime.
Fastest workflow: Use Visual Studio Code with the APKLab extension to automatically decompile, modify, recompile, sign, and install without running any commands. Also useful: apk.sh .
The Smali Workflow
This gives you Smali code and resources. Key files to inspect:
res/values/strings.xml (and all XMLs under res/values/*)
AndroidManifest.xml
Any .sqlite or .db files
If apktool has trouble decoding, try apktool d APP.apk -r (skip resource decoding).
Step 2 — Modify Smali Code
Smali is the human-readable representation of Dalvik bytecode. Reference for opcodes: http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html
Hello World Example
Java source:
public static void printHelloWorld () {
System . out . println ( "Hello World" )
}
Equivalent Smali:
.method public static printHelloWorld()V
.registers 2
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
const-string v1, "Hello World"
invoke-virtual {v0,v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
return-void
.end method
Common Light Modifications
# Modify constant values
const v9, 0xf4240
const/4 v8, 0x1
const-string v5, "wins"
# Math operations
add-int/lit8 v0, v2, 0x1 # v2 + 1, store in v0
mul-int v0,v2,0x2 # v2 * 2, store in v0
# Move values
move v1,v2
# Conditionals
if-ge # Greater or equals
if-le # Less or equals
if-eq # Equals
# Get/set object attributes
iget v0, p0, Lcom/example/GameActivity;->score:I # this.score → v0
iput v0, p0, Lcom/example/GameActivity;->score:I # v0 → this.score
# Jumps
:goto_6
if-ne v0, v9, :goto_6
goto :goto_6
Adding Log Output
# Log "wins: <number>"
iget v5, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I
invoke-static {v5}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v1
const-string v5, "wins"
invoke-static {v5, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
Injecting System.loadLibrary() Early
To preload a native library in a static initializer:
.class public Lcom/example/App;
.super Landroid/app/Application;
.method static constructor <clinit>()V
.registers 1
const-string v0, "sotap"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
return-void
.end method
Alternatively in Application.onCreate():
.method public onCreate()V
.locals 1
const-string v0, "sotap"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
invoke-super {p0}, Landroid/app/Application;->onCreate()V
return-void
.end method
Step 3 — Recompile
# Run from the folder generated by apktool d
apktool b .
# Output appears in ./dist/
Step 4 — Sign the APK
# Generate a signing key
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 \
-validity 10000 -alias myalias
# Sign with jarsigner
jarsigner -keystore key.jks path/to/dist/app.apk myalias
# Align with zipalign
zipalign -v 4 infile.apk outfile.apk
# Or sign with apksigner (after zipalign)
apksigner sign --ks key.jks ./dist/mycompiled.apk
Sign either with jarsigner (before zipalign) or with apksigner (after zipalign) — not both. Using both will break the signature.
Understanding Dalvik / ART
Android apps are written in Java or Kotlin and compiled to Dalvik Executable (DEX) bytecode
The Android Runtime (ART) uses Ahead-of-Time (AOT) compilation of DEX to native code
Smali is the assembly language for DEX — the human-readable form
baksmali disassembles DEX to Smali; smali assembles Smali back to DEX
References