Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Automatically extract KeyStore objects and relative password from Android applications with Frida - Read more: http://ceres-c.it/frida-android-keystore/
#!/usr/bin/python3
'''
author: ceres-c
usage: ./frida-extract-keystore.py
Once the keystore(s) have been exported you have to convert them to PKCS12 using keytool
'''
import frida, sys, time
app_name = 'com.app.mobile'
i = 0
ext = ''
def on_message(message, data):
global i, ext
if (message['type'] == 'send' and 'event' in message['payload']):
if (message['payload']['event'] == '+found'):
i += 1
print("\n[+] Hooked keystore" + str(i) + "...")
elif (message['payload']['event'] == '+type'):
print(" [+] Cert Type: " + ''.join(message['payload']['certType']))
if (message['payload']['certType'] == 'PKCS12'):
ext = '.jks'
elif (message['payload']['event'] == '+pass'):
print(" [+] Password: " + ''.join(message['payload']['password']))
elif (message['payload']['event'] == '+write'):
print(" [+] Writing to file: keystore" + str(i) + ext)
f = open('keystore' + str(i) + ext, 'wb')
f.write(bytes.fromhex(message['payload']['cert']))
f.close()
else:
print(message)
jscode = """
setTimeout(function() {
Java.perform(function () {
keyStoreLoadStream = Java.use('java.security.KeyStore')['load'].overload('java.io.InputStream', '[C');
/* following function hooks to a Keystore.load(InputStream stream, char[] password) */
keyStoreLoadStream.implementation = function(stream, charArray) {
/* sometimes this happen, I have no idea why, tho... */
if (stream == null) {
/* just to avoid interfering with app's flow */
this.load(stream, charArray);
return;
}
/* just to notice the client we've hooked a KeyStore.load */
send({event: '+found'});
/* read the buffer stream to a variable */
var hexString = readStreamToHex (stream);
/* send KeyStore type to client shell */
send({event: '+type', certType: this.getType()});
/* send KeyStore password to client shell */
send({event: '+pass', password: charArray});
/* send the string representation to client shell */
send({event: '+write', cert: hexString});
/* call the original implementation of 'load' */
this.load(stream, charArray);
/* no need to return anything */
}
});
},0);
/* following function reads an InputStream and returns an ASCII char representation of it */
function readStreamToHex (stream) {
var data = [];
var byteRead = stream.read();
while (byteRead != -1)
{
data.push( ('0' + (byteRead & 0xFF).toString(16)).slice(-2) );
/* <---------------- binary to hex ---------------> */
byteRead = stream.read();
}
stream.close();
return data.join('');
}
"""
print("[.] Attaching to device...")
try:
device = frida.get_usb_device()
except:
print("[-] Can't attach. Is the device connected?")
sys.exit()
print("[.] Spawning the app...")
try:
pid = device.spawn(app_name)
device.resume(pid)
time.sleep(1)
except:
print("[-] Can't spawn the App. Is filename correct?")
sys.exit()
print("[.] Attaching to process...")
try:
process = device.attach(pid)
except:
print("[-] Can't connect to App.")
sys.exit()
print("[.] Launching js code...")
print(" (run the app until needed, close it and then kill this script)")
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
try:
sys.stdin.read()
except KeyboardInterrupt:
print ("\nExiting now")
exit(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.