-
Notifications
You must be signed in to change notification settings - Fork 3
Frida
CCint3 edited this page Feb 24, 2020
·
7 revisions
var b = new ArrayBuffer(10);
var n = new Uint8Array(b);
n[0] = 0xFF;
n[1] = 0xFE;
console.log(n);var bytes = xxx; // 由Frida Hook或其它方式获取到该数据
for (var i = 0; i < bytes.length; i++) {
console.log(i + ": " + bytes[i]);
}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 与其包装类的 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.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.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]);
}
});请使用V8引擎运行以下脚本例如:
frida -U -f com.ss.android.ugc.aweme --runtime=v8 -o frida.log --no-pause -l script.jsconst 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.");工欲善其事必先利其器;
纸上得来终觉浅,须知此事要躬行;
智者不惑行者无疆;大将无能累死三军;
由简入奢易,由奢入简难;这句话背后藏着的是我们可以戒掉痛苦,但是戒不掉快乐;