4

I am trying to obtain the SecretKey passed to the decryptAesCipherText function. I hooked the function in Frida to try to print out the arguments when the method is called but since SecretKey is an object, all attempts to print it out give output as [object Object]. However the SecretKey object has a method getEncoded() which will return a byte array which can be printed out in hex format. How can I call this method from Frida and get the result?

The java function, I am hooking to is given below

import javax.crypto.Cipher;
import javax.crypto.SecretKey;

private byte[] decryptAesCipherText(SecretKey secretKey, byte[] bArr) {
        Cipher instance = Cipher.getInstance("AES/ECB/PKCS5Padding");
        instance.init(2, secretKey);
        return decryptCipherText(instance, bArr);
}



The javascript snippet (incomplete) to hook the function

var target_class = Java.use('com.reactlibrary.securekeystore.RNSecureKeyStoreModule');

target_class.decryptAesCipherText.overload('javax.crypto.SecretKey','[B').implementation = function(key, array){
        console.log("Inside decrypt aes");

        //Call getEncoded method on key to get byte array

        var ret = my_class.decryptAesCipherText.overload('javax.crypto.SecretKey','[B').call(this, key, array);
        return ret;
}
Abin K Paul
  • 163
  • 2
  • 10

1 Answers1

4

It seems like you can't call getEncoded on the javax.crypto.SecretKey interface.

Usually the SecretKey parameter is of type javax.crypto.spec.SecretKeySpec and if you type cast the key parameter to SecretKeySpec you can can call getEncoded() and print the used key:

function encodeHex(byteArray) {
    const HexClass = Java.use('org.apache.commons.codec.binary.Hex');
    const StringClass = Java.use('java.lang.String');
    const hexChars = HexClass.encodeHex(byteArray);
    return StringClass.$new(hexChars).toString();
}

Java.perform(function x() {
    const target_class = Java.use('com.example.myapplication.MainActivity');
    target_class.decryptAesCipherText.overload('javax.crypto.SecretKey', '[B').implementation = function (key, array) {
        console.log("Inside decrypt aes");

        const secretKeySpec = Java.cast(key, Java.use('javax.crypto.spec.SecretKeySpec'));
        const encodedKey = secretKeySpec.getEncoded();

        // print the key bytes as hex value
        console.log("KEY: " + encodeHex(encodedKey));

        var ret = my_class.decryptAesCipherText.overload('javax.crypto.SecretKey', '[B').call(this, key, array);
        return ret;
    }

});
Robert
  • 39,162
  • 17
  • 99
  • 152
  • in my case casting to `javax.crypto.spec.SecretKeySpec` did not work! but casting to `java.security.Key` did work! anyway up :) – arman Jun 01 '20 at 15:26
  • 1
    Thanks for the solution. It works perfectly. Just a quick another question. Is it generally not possible to call methods on interfaces from Frida or just in this case ? – Abin K Paul Jun 02 '20 at 08:11
  • 1
    @AbinKPaul This is a good question. I don't have much experience with interfaces, but as you discovered that type casting to `java.security.Key` works. As it is a super interface of `SecretKey` and the interface that defines `getEncoded()`, it may be possible that in interfaces you have to use the interface that defines the method (may be an interface inheritance problem in Frida?). – Robert Jun 03 '20 at 07:15
  • 1
    Interface method has no body so we can't call them! It is a collection of abstract methods. https://www.tutorialspoint.com/java/java_interfaces.htm. but casting to them is possible and as I casted `key` to `java.security.Key` I can call `kes`'s class methods. even in pure java casting `key` to `javax.crypto.spec.SecretKeySpec` did not work! – arman Jun 04 '20 at 05:38