Skip to content

Commit 361f284

Browse files
author
HackTricks News Bot
committed
Add content from: Research Update Enhanced src/mobile-pentesting/android-app-p...
1 parent f60651e commit 361f284

1 file changed

Lines changed: 76 additions & 1 deletion

File tree

src/mobile-pentesting/android-app-pentesting/smali-changes.md

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,22 @@ Using **Visual Studio Code** and the [APKLab](https://github.com/APKLab/APKLab)
1313

1414
Another **script** that facilitates this task a lot is [**https://github.com/ax/apk.sh**](https://github.com/ax/apk.sh)
1515

16+
### Split APKs / App Bundles
17+
18+
Modern targets are commonly delivered as **split APKs** (`base.apk` + `split_config.*.apk`) instead of a single monolithic APK. If you patch only `base.apk`, resources or native libraries can go out of sync and the installation may fail.
19+
20+
Quick triage from a device:
21+
22+
```bash
23+
adb shell pm path com.example.app
24+
adb pull /data/app/.../base.apk
25+
adb pull /data/app/.../split_config.arm64_v8a.apk
26+
adb pull /data/app/.../split_config.en.apk
27+
```
28+
29+
If the target is a split package, either rebuild the whole set or use tooling that **joins the APKs first**. [**apk.sh**](https://github.com/ax/apk.sh) is handy here because it can combine split APKs into a single patchable APK and fix public resource identifiers.\
30+
For Frida/Objection-oriented repacking workflows, also check [Android Anti-Instrumentation & SSL Pinning Bypass](android-anti-instrumentation-and-ssl-pinning-bypass.md).
31+
1632
## Decompile the APK
1733

1834
Using APKTool you can access to the **smali code and resources**:
@@ -67,6 +83,8 @@ Finally, **sign** the new APK:
6783
jarsigner -keystore key.jks path/to/dist/* <your-alias>
6884
```
6985

86+
`jarsigner` still works for some quick tests, but for modern Android builds **`apksigner` is preferred** because it handles the newer APK signature schemes.
87+
7088
### Optimize new application
7189

7290
**zipalign** is an archive alignment tool that provides important optimisation to Android application (APK) files. [More information here](https://developer.android.com/studio/command-line/zipalign).
@@ -76,6 +94,12 @@ zipalign [-f] [-v] <alignment> infile.apk outfile.apk
7694
zipalign -v 4 infile.apk
7795
```
7896

97+
If the APK contains bundled native libraries (`lib/*.so`), Android now recommends using **`-P 16`** so the `.so` files are aligned for both 16 KiB and 4 KiB page-size devices:
98+
99+
```bash
100+
zipalign -P 16 -f -v 4 infile.apk outfile.apk
101+
```
102+
79103
### **Sign the new APK (again?)**
80104

81105
If you **prefer** to use [**apksigner**](https://developer.android.com/studio/command-line/) instead of jarsigner, **you should sing the apk** after applying **the optimization with** zipaling. BUT NOTICE THAT YOU ONLY HAVE TO **SIGN THE APPLCIATION ONCE** WITH jarsigner (before zipalign) OR WITH aspsigner (after zipaling).
@@ -84,6 +108,20 @@ If you **prefer** to use [**apksigner**](https://developer.android.com/studio/co
84108
apksigner sign --ks key.jks ./dist/mycompiled.apk
85109
```
86110

111+
A more practical modern flow is:
112+
113+
```bash
114+
apktool b . -o dist/app-unsigned.apk
115+
zipalign -P 16 -f -v 4 dist/app-unsigned.apk dist/app-aligned.apk
116+
apksigner sign --ks key.jks --out dist/app-signed.apk dist/app-aligned.apk
117+
apksigner verify --verbose --print-certs dist/app-signed.apk
118+
```
119+
120+
Important notes:
121+
122+
- If you **modify** an APK **after** signing it with `apksigner`, the signature is invalidated and you must sign it again.
123+
- `apksigner verify --print-certs` is useful to confirm the rebuilt APK is installable and to inspect the certificate that the target will expose at runtime.
124+
87125
## Modifying Smali
88126

89127
For the following Hello World Java code:
@@ -149,6 +187,13 @@ goto :goto_6 #Always go to: :goto_6
149187

150188
### Bigger Changes
151189

190+
### Smali gotchas that usually break rebuilds
191+
192+
- Prefer increasing **`.locals`** when you only need temporary registers in the body of an existing method. Parameter registers (`p0`, `p1`...) are mapped to the **highest** registers of the method, so switching blindly to `.registers` often breaks argument layout.
193+
- `move-result`, `move-result-wide`, and `move-result-object` **must appear immediately after** the matching `invoke-*`. Inserting logging or any other opcode between them makes the method invalid.
194+
- `long` and `double` values are **wide** values and consume a **register pair**. If you reuse those registers later, remember that `v10` also occupies `v11`.
195+
- If you need to pass many registers, or very high-numbered ones, use the `/range` variants such as `invoke-virtual/range`.
196+
152197
### Logging
153198

154199
```bash
@@ -168,6 +213,34 @@ Recommendations:
168213
- The new variables should be the next numbers of the already declared variables (in this example should be _v10_ and _v11_, remember that it starts in v0).
169214
- Change the code of the logging function and use _v10_ and _v11_ instead of _v5_ and _v1_.
170215

216+
### Patching common anti-tamper checks
217+
218+
When an app is repacked, one of the first things that may break is an in-app **signature / installer / integrity** check. Good strings to search in JADX or in the smali tree are:
219+
220+
- `GET_SIGNATURES`
221+
- `GET_SIGNING_CERTIFICATES`
222+
- `apkContentsSigners`
223+
- `MessageDigest`
224+
- `SHA-256`
225+
- `Base64`
226+
- `getInstallerPackageName`
227+
- `com.android.vending`
228+
229+
Modern apps often call `PackageManager.getPackageInfo(..., GET_SIGNING_CERTIFICATES)`, hash the signer bytes with `MessageDigest`, and compare the result with a hardcoded constant. In practice, it is usually easier to patch the **final boolean / branch** than to rewrite all the signature-handling code.
230+
231+
Example patterns:
232+
233+
```smali
234+
# Force a boolean result to "valid"
235+
const/4 v0, 0x1
236+
237+
# Or invert the branch that sends execution to the tamper handler
238+
if-eqz v0, :tamper_detected # original
239+
if-nez v0, :tamper_detected # patched
240+
```
241+
242+
If the verification code is noisy, look for the **last comparison** before the error dialog / `finish()` / `System.exit()` / telemetry call and patch there instead of touching the entire routine.
243+
171244
### Toasting
172245

173246
Remember to add 3 to the number of _.locals_ at the beginning of the function.
@@ -223,5 +296,7 @@ Notes:
223296
## References
224297

225298
- SoTap: Lightweight in-app JNI (.so) behavior logger – [github.com/RezaArbabBot/SoTap](https://github.com/RezaArbabBot/SoTap)
299+
- Android Developers: [apksigner](https://developer.android.com/tools/apksigner) and [zipalign](https://developer.android.com/tools/zipalign)
300+
- apk.sh: [github.com/ax/apk.sh](https://github.com/ax/apk.sh)
226301

227-
{{#include ../../banners/hacktricks-training.md}}
302+
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)