Skip to content

Instantly share code, notes, and snippets.

@roccatommaso
Last active December 7, 2025 11:47
Show Gist options
  • Select an option

  • Save roccatommaso/88178636de23aec1bbc6d3445b904438 to your computer and use it in GitHub Desktop.

Select an option

Save roccatommaso/88178636de23aec1bbc6d3445b904438 to your computer and use it in GitHub Desktop.

Largely based on this work of Marco Aceti.

The main difference is the way the keystore is obtained, making the application debuggable instead of using adb backup (that has been "fixed").

What is SPID?

Search on the Internet mate or ask GPT.

Why is this needed?

Because the PosteId app is frustrating; I want to manage all my OTP credentials with the same app.

0. Preliminary steps

You should have installed adb, apktool, apksigner, zipalign, python3 and rg.

I noticed that the newest versions of apktool throw errors when rebuilding; the version that worked for me was 2.11.0.

Creating a Python virtual environment

python3 -m venv .env && \
source .env/bin/activate && \
python -m pip install pyjks asn1;

1. Modify the existing application

All Android apps are now distributed as an App Bundle, i.e., a collection of APK files each serving a specific purpose. We need to download every APK and patch them all.

1. Extract the APKs from the phone

for apk in $(adb shell pm path posteitaliane.posteapp.appposteid | awk -F':' '{print $2}'); do
    adb pull "$apk"
done

2. Decode the extracted APKs with apktool

for apk in *.apk; do 
    apktool d -f $apk
done

3. Change every occurrence of the current applicationId

Normally we would have to uninstall the original app before installing the patched one, because Android treats the same applicationId as the same package and refuses two differently signed copies. So, let’s rename the applicationId throughout the decompiled sources.

# Find and replace every occurrence of the string 'posteitaliane.posteapp.appposteid' in all non‑markdown files
rg -l 'posteitaliane\.posteapp\.appposteid' -g !'*.md' \
| xargs sed -i 's/posteitaliane\.posteapp\.appposteid/posteitaliane.posteapp.apppatchedid/g'

# Same thing, but with a slightly different string
rg -l 'posteitaliane/posteapp/appposteid' -g !'*.md' \
| xargs sed -i 's/posteitaliane\/posteapp\/appposteid/posteitaliane\/posteapp\/apppatchedid/g'

# Rename all directories that contain the structure posteitaliane/posteapp/appposteid
fd appposteid -x mv {} {//}/apppatchedid

# Finally, adjust the <permission> tag in AndroidManifest.xml because two apps with different signatures cannot declare the same permission.
rg -l 'it.posteitaliane.provider.READ_DATA_PERMISSION' -g !'*.md' \
| xargs sed -i 's/it.posteitaliane.provider.READ_DATA_PERMISSION/it.patcheditaliane.provider.READ_DATA_PERMISSION/g'

4. Build the new application

for apk in *.apk; do 
    apktool b -f -d -o "unsigned/$apk" "${apk%.*}"
done

Please note that we added the -d flag that sets android:debuggable to "true" in the APK's compiled manifest.

5. Align, sign, and verify the APKs

Google requires every installable APK to be cryptographically signed.

# allineare tutti gli apks
if [[ ! -d "aligned" ]]; then
    mkdir "aligned"
fi
    
for unsigned in unsigned/*.apk; do 
    zipalign -p -f 4 "$unsigned" "aligned/${unsigned##*/}"
done

Create a keystore (named patch.keystore here):

keytool -genkeypair -v -keystore patch.keystore -keyalg RSA -keysize 2048 -validity 3650 -alias patch -storepass patched

Accept the default prompts and type y when asked for confirmation.

if [[ ! -d "signed" ]]; then
    mkdir "signed"
fi
  
#firmare tutti gli apks
for aligned in aligned/*.apk; do 
    apksigner sign --ks patch.keystore \
		--ks-pass=pass:patched \
		--out "signed/${aligned##*/}" \
		$aligned
done

6. Clean

rm -r base split_config.arm64_v8a split_config.it split_config.en split_config.xxhdpi unsigned aligned

7. Install on the phone

Now you can install signed apks like this:

adb install-multiple signed/*.apk

8. Login in the app

Login with your account in the app. Once you have done that, close it and DO NOT open it again until you have added

the seed into the authenticator.

(Small note: you can actually open the app, but you must avoid tapping “Generate temporary PIN” because that action changes the seed.)

2. Extract the keystore

1. Extract SCA_HOLDER.ubr

Previously the way to extract SCA_HOLDER.ubr was to do a backup of the

application and

Tu do so, we can use the following command: ```bash adb shell run-as

posteitaliane.posteapp.apppatchedid cat

/data/data/posteitaliane.posteapp.apppatchedid/files/SCA_HOLDER.ubr >

SCA_HOLDER.ubr ```

Now you will have the beautiful file that you were searching for in the current

directory.

2. Decrypt and retrieve the seed

The following Python script reads the UberKeyStore file, extracts the secret, and prints the Base32‑encoded seed.

import jks
import asn1
import base64

ks = jks.bks.UberKeyStore.load('SCA_HOLDER.ubr', 'SCA_HOLDER') 
c = ks.entries['_APP_SECRET'].cert 

decoder = asn1.Decoder()
decoder.start(c)
decoded = decoder.read()
ski = decoded[1][0][-1][0][0][1]   

seed = base64.b32encode(ski).rstrip(b"=").decode('utf-8')
print(seed)

Add this seed to your favourite authenticator with these settings:

Setting Value
Hash function SHA1
Period 120
Digits 6

Now compare the TOTP generated by your authenticator with the one shown in the PosteId app—if they match, you’ve have done it!

Closing steps

You can now delete everything in this folder, including the intermediate build artefacts, and the PosteId app.

Hope that's helpfull for someone else other than me!

@tatore02
Copy link

tatore02 commented Dec 6, 2025

I have done correctly all the steps for modifying the original app, but when I want to start it on the device I get an error: "Si è verificato un errore in fase di avvio dell'App. Ti consigliamo di riprovare e di controllare l'eventuale disponibilità sullo store di aggiornamenti dell'app"

@roccatommaso
Copy link
Author

roccatommaso commented Dec 6, 2025 via email

@tatore02
Copy link

tatore02 commented Dec 7, 2025

I'm using the last version (4.11.9)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment