Skip to content
CCint3 edited this page Feb 24, 2020 · 7 revisions

JavaScript生成Array

var b = new ArrayBuffer(10);
var n = new Uint8Array(b);
n[0] = 0xFF;
n[1] = 0xFE;
console.log(n);

遍历Java的[B类型数据

var bytes = xxx; // 由Frida Hook或其它方式获取到该数据
for (var i = 0; i < bytes.length; i++) {
  console.log(i + ": " + bytes[i]);
}

Multi DEX

Java.perform(function () {
  var jApplication = Java.use("android.app.Application");
  jApplication.attachBaseContext.implementation = function () {
    var tag = "Application.attachBaseContext";
    var log = "";
    var thread = jThread.currentThread();
    var tid = gettid();
    var tname = thread.getName();
    var retval;
    log += "> - - - - tid:[" + tid + "] tname:[" + tname + "] - - - - <\n";
    log += tag + " Enter.\n";
    log += JThreadTrace2String(thread, 1) + "\n";
    console.log(log);

    retval = this.attachBaseContext.apply(this, arguments);

    Java.classFactory.loader = arguments[0].getClassLoader();  //替换 loader
    try {
      Java.classFactory.use("proto_new_gift.GiftCommonReq");
    } catch (e) {
    }
    log = tag + " Leave.\n";
    log += "  this: " + this + "\n";
    log += "^ - - - - tid:[" + tid + "] tname:[" + tname + "] - - - - ^\n";
    console.log(log);
    return retval;
  };
});

获取 Java 基础数据类型的 Class

Java 中,基础数据类型的 Class 与其包装类的 TYPE 字段等价;例如:

System.out.println("Test boolean: " + (boolean.class == java.lang.Boolean.TYPE));
System.out.println("Test Boolean: " + (boolean.class == java.lang.Boolean.class));

控制台输出:

Test boolean: true
Test Boolean: false

Java byte[] 转 JavaScript ArrayBuffer

Java.perform(function () {
  var jString = Java.use('java.lang.String');
  var bytes = jString.$new('Hello World!').getBytes();
  var u8array = new Uint8Array(bytes);
  send("hello", u8array.buffer);
});

创建Java数组

Java.perform(function () {
  let bytes = Java.array('byte', [1, 2, 3]);
  for (let i in bytes) {
    if (!bytes.hasOwnProperty(i))
      continue;
    console.log(i + ": " + bytes[i]);
  }
});

好用的Frida脚本

请使用V8引擎运行以下脚本例如:

frida -U -f com.ss.android.ugc.aweme --runtime=v8 -o frida.log --no-pause -l script.js
const gettid = new NativeFunction(Module.findExportByName(null, "gettid"), "uint32", []);
const getpid = new NativeFunction(Module.findExportByName(null, "getpid"), "uint32", []);

/**
 * @return {string}
 */
function Native_ThreadTrace2String(traces, tab) {
  let module;
  let tab_str = "";
  for (let i = 0; i !== tab; i++) {
    tab_str += "  ";
  }
  const stackTraces = [];
  for (let j in traces) {
    if (!traces.hasOwnProperty(j)) continue;
    const stackTrace = new class {
      constructor(index) {
        this.index = index;
        this.moduleName = null;
        this.moduleBase = null;
        this.offset = null;
        this.address = null;
      }

      toString = function () {
        return "idx: " + this.index +
          ", name: " + this.moduleName +
          ", base: " + this.moduleBase +
          ", offset: " + this.offset +
          ", address: " + this.address;
      };
    }(j);
    module = Process.findModuleByAddress(traces[j]);
    if (module) {
      stackTrace.moduleName = module.name;
      stackTrace.moduleBase = module.base;
    }
    stackTrace.address = traces[j];
    stackTrace.offset = "0x" + (parseInt(stackTrace.address) - parseInt(stackTrace.moduleBase)).toString(16);
    stackTraces.push(stackTrace);
  }
  return tab_str + stackTraces.join('\n' + tab_str);
}

/**
 * @return {string}
 */
function Java_ThreadTrace2String(thread, tabsize) {
  let tab_str = "";
  let ret;
  const stack_trace = thread.getStackTrace();
  stack_trace.shift();
  stack_trace.shift();
  for (let i = 0; i < tabsize; i++) {
    tab_str += "  ";
  }
  ret = tab_str + "Thread Stack Trace:\n";
  ret += tab_str + "  " + stack_trace.join("\n" + tab_str + "  ");
  return ret;
}

class Reflection {
  // private static field.
  static __classes__ = {};

  // private static method.
  static __LoadClass__ = function (className) {
    let ret = Reflection.__classes__[className];
    if (!ret)
      ret = Reflection.__classes__[className] = new class {
        constructor(className) {
          this.className = className;
          this.useClass = Java.use(className);
        }

        get primitiveClass() {
          if (!this.__primitiveClass__)
            this.__primitiveClass__ = this.useClass.class.getDeclaredField("TYPE").get(null);
          return this.__primitiveClass__;
        }

        get componentClass() {
          if (!this.__componentClass__)
            switch (this.className) {
              case 'java.lang.Boolean':
                this.__componentClass__ = Reflection.__LoadClass__('java.lang.Class').useClass.forName('[Z');
                break;
              case 'java.lang.Character':
                this.__componentClass__ = Reflection.__LoadClass__('java.lang.Class').useClass.forName('[C');
                break;
              case 'java.lang.Byte':
                this.__componentClass__ = Reflection.__LoadClass__('java.lang.Class').useClass.forName('[B');
                break;
              case 'java.lang.Short':
                this.__componentClass__ = Reflection.__LoadClass__('java.lang.Class').useClass.forName('[S');
                break;
              case 'java.lang.Integer':
                this.__componentClass__ = Reflection.__LoadClass__('java.lang.Class').useClass.forName('[I');
                break;
              case 'java.lang.Long':
                this.__componentClass__ = Reflection.__LoadClass__('java.lang.Class').useClass.forName('[J');
                break;
              case 'java.lang.Float':
                this.__componentClass__ = Reflection.__LoadClass__('java.lang.Class').useClass.forName('[F');
                break;
              case 'java.lang.Double':
                this.__componentClass__ = Reflection.__LoadClass__('java.lang.Class').useClass.forName('[D');
                break;
              default:
                this.__componentClass__ = Reflection.__LoadClass__('java.lang.reflect.Array')
                  .useClass.newInstance(this.useClass.class, 0).getClass();
                break;
            }
          return this.__componentClass__;
        }

        $new = function () {
          return this.useClass.$new.apply(this.useClass, arguments);
        };
      }(className);
    return ret;
  };

  static get boolean() {
    return Reflection.__LoadClass__('java.lang.Boolean');
  };

  static get character() {
    return Reflection.__LoadClass__('java.lang.Character');
  };

  static get byte() {
    return Reflection.__LoadClass__('java.lang.Byte');
  };

  static get short() {
    return Reflection.__LoadClass__('java.lang.Short');
  };

  static get integer() {
    return Reflection.__LoadClass__('java.lang.Integer');
  };

  static get long() {
    return Reflection.__LoadClass__('java.lang.Long');
  };

  static get float() {
    return Reflection.__LoadClass__('java.lang.Float');
  };

  static get double() {
    return Reflection.__LoadClass__('java.lang.Double');
  };

  constructor(className) {
    this.className = className;
    this.loadedClass = Reflection.__LoadClass__(className);
    this.useClass = this.loadedClass.useClass;
    this.__methods__ = {};
    this.__fields__ = {};

    this.field = new class {
      constructor(clazz) {
        this.clazz = clazz;
      }

      find = function (name) {
        let field;
        try {
          field = this.clazz.getDeclaredField(name);
        } catch (e) {
          field = this.clazz.getField(name);
        }
        return field;
      };

      findall = function () {
        let fields;
        fields = this.clazz.getDeclaredFields();
        fields.concat(this.clazz.getFields());
        return fields;
      };

      getObj = function (name, obj) {
        let isAccessible;
        let ret;
        let field = find(name);
        isAccessible = field.isAccessible();
        if (!isAccessible) field.setAccessible(true);
        ret = field.get.overload("java.lang.Object").call(field, obj);
        if (!isAccessible) field.setAccessible(false);
        return ret;
      };

      setObj = function (name, obj, val) {
        let isAccessible;
        let field = find(name);
        isAccessible = field.isAccessible();
        if (!isAccessible) field.setAccessible(true);
        field.set.overload('java.lang.Object', 'java.lang.Object').call(field, obj, val);
        if (!isAccessible) field.setAccessible(false);
      };

      setBoolean = function (name, obj, bool) {
        let isAccessible;
        let field = find(name);
        isAccessible = field.isAccessible();
        if (!isAccessible) field.setAccessible(true);
        field.setBoolean.overload('java.lang.Object', 'boolean').call(field, obj, bool);
        if (!isAccessible) field.setAccessible(false);
      };

      setInt = function (name, obj, i) {
        let isAccessible;
        let field = find(name);
        isAccessible = field.isAccessible();
        if (!isAccessible) field.setAccessible(true);
        field.setInt.overload('java.lang.Object', 'int').call(field, obj, i);
        if (!isAccessible) field.setAccessible(false);
      };
    }(this.useClass.class);

    this.method = new class {
      constructor(clazz) {
        this.clazz = clazz;
      }

      find = function (name, ...args) {
        let method;
        try {
          method = this.clazz.getDeclaredMethod(name, args);
        } catch (e) {
          method = this.clazz.getMethod(name, args);
        }
        return function (obj, ...args) {
          let isAccessible;
          let ret;
          isAccessible = method.isAccessible();
          if (!isAccessible) method.setAccessible(true);
          ret = method.invoke(obj, args);
          if (!isAccessible) method.setAccessible(false);
          return ret;
        };
      };
    }(this.useClass.class);
  };

  get class() {
    return this.useClass.class;
  };
}

Java.perform(function () {
  let rString = new Reflection('java.lang.String');

  console.log(rString.method.find('indexOf', rString.class, Reflection.integer.primitiveClass)
    .call(null, '123', '1', Reflection.integer.$new(0)));

  console.log(rString.method.find('indexOf', rString.class, Reflection.integer.primitiveClass)
    .call(null, '123', '23', Reflection.integer.$new(0)));

  console.log(rString.method.find('indexOf', rString.class, Reflection.integer.primitiveClass)
    .call(null, '123', '4', Reflection.integer.$new(0)));

  let indexOfMethod = rString.method.find('indexOf', rString.class, Reflection.integer.primitiveClass);
  console.log(indexOfMethod('123', '1', Reflection.integer.$new(0)));
  console.log(indexOfMethod('123', '23', Reflection.integer.$new(0)));
  console.log(indexOfMethod('123', '4', Reflection.integer.$new(0)));
});

console.log("ending.");

Focus Make Things

Clone this wiki locally