4

I'm trying to write a function using Frida that takes a Java object instance as an argument and returns a JS object with all the values and types of the Java object fields, possibly recursively.

For instance, if we have something like:

public class Person {
  private String fullName;
  private int age;
  private List hobbies,

  public Person(String fullName, int age, List hobbies) {
    ...
  }

  public void hello() {
    ...
  }
}

I'd like to be able (in a Frida JS script) to run something like

Java.use("Person").hello.implementation = function() {
  console.log(JSON.stringify(dumpObject(this, 2)));  // dump recursively 2 levels deep
  this.hello();
}

and see something like:

{
  "instance":"0x1234",
  "type":"Person",
  "fields' [
    {
     "name":"fullName",
     "declaredType":"java.lang.String",
     "actualType":"java.lang.String",
     "value":"John Smith",
    },
    {
     "name":"age",
     "declaredType":"int",
     "actualType":"int",
     "value":25,
    },
    {
     "name":"hobbies",
     "declaredType":"java.util.List",
     "actualType":"java.util.ArrayList",
     "value":{
        "instance":"0x4567",
        "type":"java.util.ArrayList",
        "fields": [
           ... all the fields of this ArrayList instance, 2 levels deep
        ],
     },
    },
  ]
}

I tried several different approaches, but I keep having lots of errors and problems. Before I dig deeper, is anyone aware of some existing implementation that would save me quite a bit of time? I Googled extensively, but could only find scripts that dump class methods and field names, nothing that intelligently looks at values, including corner cases requiring _name access, static members, recursive dumping, etc...

Thanks!

mme76
  • 41
  • 1
  • 3
  • Json serialization of arbitrary objects is not an easy job. You can implement it yourself using Frida, but my recommendation would be to make use of the Java environment the object(s) reside it: Use class loader to load Jackson or GSON library which contain the code for Json serialization and make use of those classes. (Note: for loading the jar files an Android you have to convert them to dex). – Robert Feb 17 '20 at 08:43

1 Answers1

2

If you have JSON library loaded in memory (or you can load it dynamically w/ Module.load) you can invoke deserialize and pass the Java instance.

If you want to do it w/ Frida you can use Java class API to enumerate fields & methods, here is a boilerplate to start from.

var BreakException = {};

function describeJavaClass(klass) {
  var limit = 100;
  Java.enumerateLoadedClassesSync().forEach(klass => {
    if (--limit < 0) throw BreakException;
    var instances = [];
    Java.choose(klass, {
      onComplete: function () { 
        if (instances.length != 0)
          console.log(JSON.stringify(instances, null, 2));
      },
      onMatch: function (instance) { 
        var _class = instance.class;
        var c = { 
          instance: instance, 
          class: klass, 
          methods: [], 
          fields: {} 
        };
        _class.getDeclaredFields().forEach(f => {
          var _field = f.toString().split('.').pop();
          var val = instance[_field].value;
          c.fields[f] = val ? val.toString() : val;
          instances.push(c);
        });
        _class.getDeclaredMethods().forEach(method => {
          c.methods.push(method.toString());
        });

      }
    });
  });
}

Java.perform(describeJavaClass);

whoopdedoo
  • 2,815
  • 23
  • 46