| name | apktool |
| description | Reverse engineer Android APKs using Apktool. Use when decoding APKs to smali and resources, rebuilding modified APKs, bypassing certificate pinning, injecting Frida gadgets, analyzing AndroidManifest.xml for attack surface, modifying network security config, or performing combined static analysis with jadx. Covers installation, decode/rebuild workflow, framework management, smali code structure, APK signing, manifest analysis, certificate pinning bypass, Frida gadget injection, and integration with jadx for full decompilation.
|
| metadata | {"author":"redhoundinfosec","version":"1.0","reference":"https://github.com/iBotPeaches/Apktool"} |
apktool Agent Skill
When to Use This Skill
Use this skill when:
- Reverse engineering Android APKs (decode resources, smali, manifests)
- Modifying APK resources, strings, layouts, or smali code and rebuilding
- Bypassing certificate pinning via network_security_config.xml modification
- Injecting Frida gadget into an APK for dynamic analysis without root
- Analyzing AndroidManifest.xml for exported components, permissions, deep links
- Installing OEM/vendor frameworks for decompiling system APKs
- Combining Apktool's resource decode with jadx's Java decompilation
What Apktool Does
Apktool decodes Android APK files into their constituent resources: smali bytecode
(Dalvik disassembly), XML resources (layouts, strings, manifests), and assets.
It can then rebuild the modified directory back into a signed APK. Unlike jadx,
which decompiles to Java source, Apktool operates at the smali level — essential
for precise modifications, resource patching, and gadget injection that require
exact bytecode control.
Installation
java -version
wget https://github.com/iBotPeaches/Apktool/releases/latest/download/apktool.jar
wget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool
chmod +x apktool
sudo mv apktool /usr/local/bin/
sudo mv apktool.jar /usr/local/bin/
brew install apktool
sudo apt install apktool
apktool --version
Core Workflow: Decode → Modify → Rebuild → Sign
apktool d target.apk
apktool b target/ -o target_modified.apk
keytool -genkey -v -keystore debug.keystore -alias debugkey \
-keyalg RSA -keysize 2048 -validity 10000 \
-storepass android -keypass android \
-dname "CN=Debug,O=Debug,C=US"
apksigner sign --ks debug.keystore --ks-key-alias debugkey \
--ks-pass pass:android --key-pass pass:android \
--out target_signed.apk target_modified.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 \
-keystore debug.keystore -storepass android \
target_modified.apk debugkey
adb install target_signed.apk
Decode Options
apktool d target.apk
apktool d target.apk -o /opt/analysis/target/
apktool d target.apk --no-src
apktool d target.apk --no-res
apktool d target.apk -f
apktool d target.apk --api 30
apktool d target.apk --keep-broken-res
apktool d -t samsung target.apk
Rebuild Options
apktool b target/
apktool b target/ -o rebuilt.apk
apktool b target/ -f
apktool b target/ --debug
apktool b target/ --use-aapt2
Framework Installation
OEM/vendor APKs depend on custom frameworks. Install them before decoding.
apktool if framework-res.apk
apktool if samsung-framework.apk -t samsung
apktool empty-framework-dir --list
ls ~/.local/share/apktool/framework/
apktool empty-framework-dir
adb pull /system/framework/framework-res.apk
apktool if framework-res.apk
apktool d /system/app/SystemUI/SystemUI.apk
Smali Code Structure
Smali is the human-readable form of Dalvik bytecode. Files map 1:1 to Java classes.
# File: smali/com/example/app/MainActivity.smali
.class public Lcom/example/app/MainActivity;
.super Landroidx/appcompat/app/AppCompatActivity;
.source "MainActivity.java"
# Fields
.field private mApiKey:Ljava/lang/String;
# Method definition
.method public onCreate(Landroid/os/Bundle;)V
.locals 2 # number of local registers (v0, v1)
# Call super
invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
# Load constant string into v0
const-string v0, "https://api.example.com"
# Assign to field
iput-object v0, p0, Lcom/example/app/MainActivity;->mBaseUrl:Ljava/lang/String;
# Call method
invoke-virtual {p0}, Lcom/example/app/MainActivity;->checkCertificate()V
return-void
.end method
Key smali register conventions:
v0, v1, v2... — local registers (count declared by .locals N)
p0 — this reference (instance methods)
p1, p2... — method parameters
AndroidManifest.xml Analysis
After decoding, inspect AndroidManifest.xml for attack surface:
cat target/AndroidManifest.xml | grep -A3 "exported"
grep -n 'exported="true"' target/AndroidManifest.xml | grep "activity"
grep -n 'exported="true"' target/AndroidManifest.xml | grep "service"
grep -n 'exported="true"' target/AndroidManifest.xml | grep "provider"
grep -n 'exported="true"' target/AndroidManifest.xml | grep "receiver"
grep -n "permission" target/AndroidManifest.xml | grep -i "READ_CONTACTS\|RECORD_AUDIO\|CAMERA\|ACCESS_FINE_LOCATION"
grep -n "scheme\|host\|pathPrefix" target/AndroidManifest.xml
grep "allowBackup" target/AndroidManifest.xml
grep "debuggable" target/AndroidManifest.xml
Certificate Pinning Bypass (network_security_config.xml)
Method 1: Modify network_security_config.xml
apktool d target.apk -o target/
grep "networkSecurityConfig" target/AndroidManifest.xml
cat > target/res/xml/network_security_config.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- Trust system CAs (default) -->
<certificates src="system" />
<!-- Trust user-installed CAs (Burp cert) -->
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>
EOF
apktool b target/ -o target_patched.apk
apksigner sign --ks debug.keystore --ks-key-alias debugkey \
--ks-pass pass:android --key-pass pass:android \
--out target_signed.apk target_patched.apk
adb install target_signed.apk
Method 2: Disable Pinning in Smali (Hard-coded pinning)
grep -r "CertificatePinner\|checkServerTrusted\|HostnameVerifier\|TrustManager" \
target/smali/ -l
Frida Gadget Injection
Inject Frida gadget into APK to enable dynamic instrumentation without root.
apktool d target.apk -o target/
ARCH=arm64-v8a
VER=$(curl -s https://api.github.com/repos/frida/frida/releases/latest | jq -r .tag_name)
wget "https://github.com/frida/frida/releases/download/${VER}/frida-gadget-${VER}-android-${ARCH}.so.xz"
unxz frida-gadget-*.so.xz
cp frida-gadget-*.so target/lib/${ARCH}/libfrida-gadget.so
apktool b target/ -o target_frida.apk
apksigner sign --ks debug.keystore --ks-key-alias debugkey \
--ks-pass pass:android --key-pass pass:android \
--out target_frida_signed.apk target_frida.apk
adb install target_frida_signed.apk
adb shell am start -n com.target.app/.MainActivity
frida -U Gadget -l your_script.js
Modifying Resources
nano target/res/values/strings.xml
grep -r "isRooted\|RootBeer\|checkRootMethod" target/smali/ -l
Integration with jadx
Apktool + jadx together provide the complete static analysis workflow:
jadx target.apk -d jadx_output/
apktool d target.apk -o apktool_output/
grep -r "http\|https" jadx_output/sources/ | grep -v ".class"
grep -r "password\|secret\|api_key\|token" jadx_output/sources/ -i
Common Smali Patching Patterns
# Disable boolean check (make method always return true)
.method public isLicensed()Z
.locals 1
const/4 v0, 0x1 # 0x1 = true
return v0
.end method
# Disable boolean check (always return false — e.g., isRooted)
.method public isRooted()Z
.locals 1
const/4 v0, 0x0 # 0x0 = false
return v0
.end method
# Disable void method (no-op a validation function)
.method public checkLicense()V
.locals 0
return-void
.end method
# Replace hardcoded URL
# Find: const-string v0, "https://prod.api.example.com"
# Replace with: const-string v0, "http://192.168.1.10:8080"
Troubleshooting
brut.androlib.AndrolibException: Could not decode arsc file: App uses
non-standard resource encoding. Try --keep-broken-res flag.
aapt: error: Rebuild fails with resource errors. Use --use-aapt2 flag.
If still failing, check that modified XML is valid (no syntax errors).
INSTALL_FAILED_UPDATE_INCOMPATIBLE: Signed with different key than installed version.
Uninstall first: adb uninstall com.target.app
INSTALL_PARSE_FAILED_NO_CERTIFICATES: APK not signed. Run apksigner step.
Smali compile error: Check that register count in .locals N matches actual
register usage. Adding instructions may require incrementing .locals.
Framework not found: Pull from device first:
adb pull /system/framework/framework-res.apk && apktool if framework-res.apk
App crashes after patch: Dalvik verifier rejected bytecode. Verify smali
syntax with smali/baksmali tools: java -jar baksmali.jar d classes.dex
Built by Red Hound InfoSec — On-demand offensive security expertise for SMBs.
20+ years of Fortune 500 experience. Penetration testing, attack surface analysis, and security consulting.
redhound.us | GitHub | Book a consultation