An interface is a reference type in Java. It is similar to class. It is a collection of abstract methods. A class implements an interface, thereby inheriting the abstract methods of the interface.
Along with abstract methods, an interface may also contain constants, default methods, static methods, and nested types. Method bodies exist only for default methods and static methods.
An interface is different from a class in several ways:
To test this functionality I’ve created in the application an interface called MyInterface, and a class that implements the interface called MyInterfaceClass.
In order to get the interface representation in Frida we use the same code as we would use for a class:
MyInterface = Java.use("com.blog.testfrida.interfaces.MyInterface");
We can’t intercept or modify the abstract methods exposed by the interface. As an example I tried to implement the getMessage method from the interface in the following way:
MyInterface.getMessage.implementation = function () {
console.log("it gets into the getMessage");
return String.$new("it works");
}
When we call the getMessage from the implementation of the getMessage method in the MyInterfaceClass, the console.log is not triggered. If we want to change the implementation, we have to do it in each class the abstract method is implemented. In this case we did it on the only class implementing MyInterface:
var MyInterfaceClass = Java.use("com.blog.testfrida.interfaces.MyInterfaceClass");
MyInterfaceClass.getMessage.implementation = function () {
console.log("it gets into the getMessage");
return String.$new("it works");
}
Note that we can’t instantiate an interface, it will throw the following error:
Error: no supported overloads
at makeConstructor (frida/node_modules/frida-java-bridge/lib/class-factory.js:478) ...
at /examples.js:434
When we get an instance of a class that implements an interface, we can call the interfaces’ methods, but Frida will end up calling the classes implementations as in the following examples:
//we get an instance of Interface and call the getMessage
var interfaceInstance = MyInterfaceClass.getNewInstance();
//internally it calls the getMessage from the MyInterfaceClass
console.log(interfaceInstance.getMessage());
//this does not call the default interface, it calls the class one (even when it is
//casted as a MyInterface interface)
console.log(interfaceInstance.getInt());
Next: Inner classes