Skip to content

Instantly share code, notes, and snippets.

@SeeFlowerX
Created July 16, 2021 15:23
Show Gist options
  • Save SeeFlowerX/373101e86529ae04807f634b87ac4c7c to your computer and use it in GitHub Desktop.
Save SeeFlowerX/373101e86529ae04807f634b87ac4c7c to your computer and use it in GitHub Desktop.
libpoxy_star.so分析hook脚本
let jni_struct_array = [
"reserved0", "reserved1", "reserved2", "reserved3", "GetVersion", "DefineClass", "FindClass", "FromReflectedMethod", "FromReflectedField", "ToReflectedMethod", "GetSuperclass", "IsAssignableFrom", "ToReflectedField", "Throw", "ThrowNew",
"ExceptionOccurred", "ExceptionDescribe", "ExceptionClear", "FatalError", "PushLocalFrame", "PopLocalFrame", "NewGlobalRef", "DeleteGlobalRef", "DeleteLocalRef", "IsSameObject", "NewLocalRef", "EnsureLocalCapacity", "AllocObject", "NewObject",
"NewObjectV", "NewObjectA", "GetObjectClass", "IsInstanceOf", "GetMethodID", "CallObjectMethod", "CallObjectMethodV", "CallObjectMethodA", "CallBooleanMethod", "CallBooleanMethodV", "CallBooleanMethodA", "CallByteMethod", "CallByteMethodV",
"CallByteMethodA", "CallCharMethod", "CallCharMethodV", "CallCharMethodA", "CallShortMethod", "CallShortMethodV", "CallShortMethodA", "CallIntMethod", "CallIntMethodV", "CallIntMethodA", "CallLongMethod", "CallLongMethodV", "CallLongMethodA",
"CallFloatMethod", "CallFloatMethodV", "CallFloatMethodA", "CallDoubleMethod", "CallDoubleMethodV", "CallDoubleMethodA", "CallVoidMethod", "CallVoidMethodV", "CallVoidMethodA", "CallNonvirtualObjectMethod", "CallNonvirtualObjectMethodV",
"CallNonvirtualObjectMethodA", "CallNonvirtualBooleanMethod", "CallNonvirtualBooleanMethodV", "CallNonvirtualBooleanMethodA", "CallNonvirtualByteMethod", "CallNonvirtualByteMethodV", "CallNonvirtualByteMethodA", "CallNonvirtualCharMethod",
"CallNonvirtualCharMethodV", "CallNonvirtualCharMethodA", "CallNonvirtualShortMethod", "CallNonvirtualShortMethodV", "CallNonvirtualShortMethodA", "CallNonvirtualIntMethod", "CallNonvirtualIntMethodV", "CallNonvirtualIntMethodA",
"CallNonvirtualLongMethod", "CallNonvirtualLongMethodV", "CallNonvirtualLongMethodA", "CallNonvirtualFloatMethod", "CallNonvirtualFloatMethodV", "CallNonvirtualFloatMethodA", "CallNonvirtualDoubleMethod", "CallNonvirtualDoubleMethodV",
"CallNonvirtualDoubleMethodA", "CallNonvirtualVoidMethod", "CallNonvirtualVoidMethodV", "CallNonvirtualVoidMethodA", "GetFieldID", "GetObjectField", "GetBooleanField", "GetByteField", "GetCharField", "GetShortField", "GetIntField",
"GetLongField", "GetFloatField", "GetDoubleField", "SetObjectField", "SetBooleanField", "SetByteField", "SetCharField", "SetShortField", "SetIntField", "SetLongField", "SetFloatField", "SetDoubleField", "GetStaticMethodID",
"CallStaticObjectMethod", "CallStaticObjectMethodV", "CallStaticObjectMethodA", "CallStaticBooleanMethod", "CallStaticBooleanMethodV", "CallStaticBooleanMethodA", "CallStaticByteMethod", "CallStaticByteMethodV", "CallStaticByteMethodA",
"CallStaticCharMethod", "CallStaticCharMethodV", "CallStaticCharMethodA", "CallStaticShortMethod", "CallStaticShortMethodV", "CallStaticShortMethodA", "CallStaticIntMethod", "CallStaticIntMethodV", "CallStaticIntMethodA", "CallStaticLongMethod",
"CallStaticLongMethodV", "CallStaticLongMethodA", "CallStaticFloatMethod", "CallStaticFloatMethodV", "CallStaticFloatMethodA", "CallStaticDoubleMethod", "CallStaticDoubleMethodV", "CallStaticDoubleMethodA", "CallStaticVoidMethod",
"CallStaticVoidMethodV", "CallStaticVoidMethodA", "GetStaticFieldID", "GetStaticObjectField", "GetStaticBooleanField", "GetStaticByteField", "GetStaticCharField", "GetStaticShortField", "GetStaticIntField", "GetStaticLongField",
"GetStaticFloatField", "GetStaticDoubleField", "SetStaticObjectField", "SetStaticBooleanField", "SetStaticByteField", "SetStaticCharField", "SetStaticShortField", "SetStaticIntField", "SetStaticLongField", "SetStaticFloatField",
"SetStaticDoubleField", "NewString", "GetStringLength", "GetStringChars", "ReleaseStringChars", "NewStringUTF", "GetStringUTFLength", "GetStringUTFChars", "ReleaseStringUTFChars", "GetArrayLength", "NewObjectArray", "GetObjectArrayElement",
"SetObjectArrayElement", "NewBooleanArray", "NewByteArray", "NewCharArray", "NewShortArray", "NewIntArray", "NewLongArray", "NewFloatArray", "NewDoubleArray", "GetBooleanArrayElements", "GetByteArrayElements", "GetCharArrayElements",
"GetShortArrayElements", "GetIntArrayElements", "GetLongArrayElements", "GetFloatArrayElements", "GetDoubleArrayElements", "ReleaseBooleanArrayElements", "ReleaseByteArrayElements", "ReleaseCharArrayElements", "ReleaseShortArrayElements",
"ReleaseIntArrayElements", "ReleaseLongArrayElements", "ReleaseFloatArrayElements", "ReleaseDoubleArrayElements", "GetBooleanArrayRegion", "GetByteArrayRegion", "GetCharArrayRegion", "GetShortArrayRegion", "GetIntArrayRegion",
"GetLongArrayRegion", "GetFloatArrayRegion", "GetDoubleArrayRegion", "SetBooleanArrayRegion", "SetByteArrayRegion", "SetCharArrayRegion", "SetShortArrayRegion", "SetIntArrayRegion", "SetLongArrayRegion", "SetFloatArrayRegion",
"SetDoubleArrayRegion", "RegisterNatives", "UnregisterNatives", "MonitorEnter", "MonitorExit", "GetJavaVM", "GetStringRegion", "GetStringUTFRegion", "GetPrimitiveArrayCritical", "ReleasePrimitiveArrayCritical", "GetStringCritical",
"ReleaseStringCritical", "NewWeakGlobalRef", "DeleteWeakGlobalRef", "ExceptionCheck", "NewDirectByteBuffer", "GetDirectBufferAddress", "GetDirectBufferCapacity", "GetObjectRefType"
]
function getJNIFunctionAdress(func_name){
// 通过函数名获取到对应的jni函数地址
let jnienv_addr = Java.vm.getEnv().handle.readPointer()
let offset = jni_struct_array.indexOf(func_name) * Process.pointerSize;
return Memory.readPointer(jnienv_addr.add(offset))
}
function hook_jni(func_name){
let listener = null;
switch (func_name){
case "SetByteArrayRegion":
listener = Interceptor.attach(getJNIFunctionAdress(func_name), {
onEnter: function(args){
console.log(`env->${func_name} called from ${Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n")}`);
this.arg_array = args[1];
},
onLeave: function(retval){
jbhexdump(this.arg_array);
console.log("SetByteArrayRegion onLeave");
}
})
default:
listener = Interceptor.attach(getJNIFunctionAdress(func_name), {
onEnter: function(args){
console.log(`env->${func_name} called from ${Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n")}`);
}
})
}
return listener;
}
function jhexdump(array) {
if(!array) return;
console.log("---------jhexdump start---------");
var ptr = Memory.alloc(array.length);
for(var i = 0; i < array.length; ++i)
Memory.writeS8(ptr.add(i), array[i]);
console.log(hexdump(ptr, {offset: 0, length: array.length, header: false, ansi: false}));
console.log("---------jhexdump end---------");
}
function jbhexdump(array) {
console.log("---------jbhexdump start---------");
let env = Java.vm.getEnv();
let size = env.getArrayLength(array);
let data = env.getByteArrayElements(array);
console.log(hexdump(data, {offset: 0, length: size, header: false, ansi: false}));
env.releaseByteArrayElements(array, data, 0);
console.log("---------jbhexdump end---------");
}
function dumpByteArray(obj){
console.log("---------dumpByteArray start---------");
let obj_ptr = ptr(obj.$h).readPointer();
let buf_ptr = obj_ptr.add(Process.pointerSize * 3);
let size = obj_ptr.add(Process.pointerSize * 2).readU32();
console.log(hexdump(buf_ptr, {offset: 0, length: size, header: false, ansi: false}));
console.log("---------dumpByteArray end---------");
}
function getByte_LogArgs(){
Java.perform(function(){
let gson = Java.use('com.google.gson.Gson');
let ByteDataCls = Java.use("com.tencent.starprotocol.ByteData");
ByteDataCls.getByte.overload("android.content.Context", "long", "long", "long", "long", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object").implementation = function(context, num1, num2, num3, num4, obj1, obj2, obj3, obj4){
console.log(context, num1, num2, num3, num4);
console.log("obj1", obj1.$className, gson.$new().toJson(obj1))
console.log("obj2", obj2.$className, gson.$new().toJson(obj2))
console.log("obj3", obj3.$className, gson.$new().toJson(obj3))
console.log("obj4", obj4.$className, gson.$new().toJson(obj4))
dumpByteArray(obj4);
let resp = this.getByte(context, num1, num2, num3, num4, obj1, obj2, obj3, obj4)
jhexdump(resp);
return resp
}
})
}
function freeze_funcs(){
let lrand48_addr = Module.findExportByName("libc.so", "lrand48");
Interceptor.attach(lrand48_addr, {onLeave: function(retval){retval.replace(7)}});
let tm_s = 1626403551;
let tm_us = 151606;
let gettimeofday_addr = Module.findExportByName("libc.so", "gettimeofday");
Interceptor.attach(gettimeofday_addr, {
onEnter: function(args) {
this.tm_ptr = args[0];
},
onLeave:function(retval){
this.tm_ptr.writeLong(tm_s);
this.tm_ptr.add(0x4).writeLong(tm_us);
}
});
}
function call_getByte(){
Java.perform(function(){
let LongCls = Java.use("java.lang.Long");
let StringCls = Java.use("java.lang.String");
let ReflectArrayCls = Java.use('java.lang.reflect.Array')
let ByteDataCls = Java.use("com.tencent.starprotocol.ByteData");
let ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
let num_1 = LongCls.$new(1).longValue();
let num_2 = LongCls.$new(0).longValue();
let num_3 = LongCls.$new(0).longValue();
let num_4 = LongCls.$new(0).longValue();
let obj1 = ReflectArrayCls.newInstance(StringCls.class, 9);
ReflectArrayCls.set(obj1, 0, "dl_10303");
ReflectArrayCls.set(obj1, 1, "1");
ReflectArrayCls.set(obj1, 2, "66666666666666666666666666666666");
ReflectArrayCls.set(obj1, 3, "getCKey");
ReflectArrayCls.set(obj1, 4, "888888888888888888888888888888888888");
ReflectArrayCls.set(obj1, 5, "1626403551515");
ReflectArrayCls.set(obj1, 6, "");
ReflectArrayCls.set(obj1, 7, "8.3.95.26016");
ReflectArrayCls.set(obj1, 8, "com.tencent.qqlive");
let obj2 = StringCls.$new("");
let obj3 = StringCls.$new("66666666666666666666666666666666");
let obj4 = Java.array('B', [49,54,50,54,52,48,51,53,53,49,44,110,48,48,51,57,101,121,49,109,109,100,44,110,117,108,108]);
let ByteDataIns = ByteDataCls.getInstance()
let byte = ByteDataIns.getByte(ctx, num_1, num_2, num_3, num_4, obj1, obj2, obj3, obj4);
jhexdump(byte);
Interceptor.detachAll();
})
}
function inline_hook(){
let hook_flag = false;
let base_addr = Module.getBaseAddress("libpoxy_star.so");
Interceptor.attach(base_addr.add(0xD9AC).add(1), {
onEnter: function(args){
hook_flag = true;
this.hook_jni_interceptor = hook_jni("SetByteArrayRegion");
},
onLeave: function (retval) {
hook_flag = false;
this.hook_jni_interceptor.detach();
console.log(`onLeave sub_D9AC`);
jbhexdump(retval);
}
});
Interceptor.attach(base_addr.add(0xAAE88).add(1), {
onEnter: function (args) {
if(hook_flag){
console.log(`call sub_AAE88`);
this.arg_0 = args[0];
console.log("sub_AAE88 arg_0", hexdump(args[0].readPointer()));
}
},
onLeave: function (retval) {
console.log("sub_AAE88 onLeave arg_0", hexdump(this.arg_0.readPointer()));
}
});
Interceptor.attach(base_addr.add(0xABDBC).add(1), {
onEnter: function (args) {
if(hook_flag){
console.log(`call sub_ABDBC`);
this.arg_0 = args[0];
console.log("sub_ABDBC arg_0", hexdump(args[0].readPointer()));
}
},
onLeave: function (retval) {
console.log("sub_ABDBC onLeave arg_0", hexdump(this.arg_0.readPointer()));
}
});
Interceptor.attach(base_addr.add(0xAC214).add(1), {
onEnter: function (args) {
console.log(`call sub_AC214`);
console.log("input", args[1], args[2], args[3], args[4]);
}
});
Interceptor.attach(base_addr.add(0xAD1D0).add(1), {
onEnter: function (args) {
console.log(`call sub_AD1D0`);
console.log("input", args[0], args[1], args[3]);
console.log(hexdump(args[2].readByteArray(args[3].toUInt32())));
}
});
Interceptor.attach(base_addr.add(0x139A4).add(1), {
onLeave: function (retval) {
console.log("sub_139A4 retval", retval.readPointer());
}
});
Interceptor.attach(base_addr.add(0x82648).add(1), {
onEnter: function (args) {
console.log(`call sub_82648`);
console.log("arg_1", hexdump(args[1].readByteArray(args[2].toUInt32())))
console.log("arg_2", args[2].toUInt32())
}
});
Interceptor.attach(base_addr.add(0x84890).add(1), {
onEnter: function (args) {
this.arg_1 = args[1];
},
onLeave: function (retval) {
console.log(`sub_84890 onLeave`);
console.log("arg_1", hexdump(this.arg_1))
}
});
Interceptor.attach(base_addr.add(0x85A40).add(1), {
onEnter: function (args) {
console.log(`call sub_85A40`);
console.log("sub_85A40 arg_1", hexdump(args[1].readByteArray(args[2].toUInt32())));
console.log("sub_85A40 arg_2", args[2]);
console.log("sub_85A40 arg_3", hexdump(args[3].readByteArray(args[4].toUInt32())));
console.log("sub_85A40 arg_4", args[4]);
}
});
Interceptor.attach(base_addr.add(0x68E44).add(1), {
onEnter: function (args) {
console.log(`call sub_68E44`);
console.log("sub_68E44 arg_1", hexdump(args[1].readByteArray(args[2].toUInt32())));
console.log("sub_68E44 arg_2", args[2]);
}
});
Interceptor.attach(base_addr.add(0x6D628).add(1), {
onEnter: function (args) {
this.arg_0 = args[0];
},
onLeave: function (retval) {
console.log("sub_6D628 retval", hexdump(this.arg_0));
}
});
Interceptor.attach(base_addr.add(0xA605C).add(1), {
onEnter: function (args) {
console.log(`call sub_A605C`);
this.arg_6 = args[6];
console.log("sub_A605C arg_1", hexdump(args[1].readByteArray(args[2].toUInt32())));
console.log("sub_A605C arg_2", args[2]);
console.log("sub_A605C arg_3", args[3]);
console.log("sub_A605C arg_4", args[4]);
console.log("sub_A605C arg_5", args[5]);
console.log("sub_A605C arg_6", hexdump(args[6]));
console.log("sub_A605C arg_7", hexdump(args[7].readByteArray(args[8].toUInt32())));
console.log("sub_A605C arg_8", args[8]);
},
onLeave: function (retval) {
console.log("sub_A605C retval", hexdump(this.arg_6));
}
});
Interceptor.attach(base_addr.add(0x9C1F0).add(1), {
onEnter: function (args) {
console.log(`call sub_9C1F0`);
this.arg_3 = args[3];
console.log("sub_9C1F0 arg_1", hexdump(args[1].readByteArray(args[2].toUInt32())));
console.log("sub_9C1F0 arg_2", args[2]);
console.log("sub_9C1F0 arg_3", hexdump(args[3]));
},
onLeave: function (retval) {
console.log("sub_9C1F0 retval", hexdump(this.arg_3));
}
});
Interceptor.attach(base_addr.add(0x9B980).add(1), {
onEnter: function (args) {
console.log(`call sub_9B980`);
this.arg_0 = args[0];
console.log("sub_9B980 arg_0", hexdump(args[0]));
console.log("sub_9B980 arg_1", hexdump(args[1].readByteArray(args[2].toUInt32())));
console.log("sub_9B980 arg_2", args[2]);
},
onLeave: function (retval) {
console.log("sub_9B980 retval", hexdump(this.arg_0));
}
});
Interceptor.attach(base_addr.add(0x86CD4).add(1), {
onEnter: function (args) {
console.log(`call sub_86CD4`);
console.log("sub_86CD4 args[1]", args[1])
console.log("sub_86CD4 args[1]", hexdump(args[1]))
console.log("sub_86CD4 args[2]", args[2])
console.log("sub_86CD4 args[3]", hexdump(args[3]))
console.log("sub_86CD4 args[4]", args[4])
console.log("sub_86CD4 args[5]", args[5])
},
onLeave: function (retval) {
}
});
Interceptor.attach(base_addr.add(0x87DD8).add(1), {
onEnter: function (args) {
console.log(`call sub_87DD8`);
this.arg_2 = args[2];
console.log("sub_87DD8 args[0]", hexdump(args[0]))
console.log("sub_87DD8 args[1]", hexdump(args[1]))
console.log("sub_87DD8 args[2]", hexdump(args[2]))
},
onLeave: function (retval) {
console.log("sub_87DD8 retval", hexdump(this.arg_2));
}
});
Interceptor.attach(base_addr.add(0x89BF4).add(1), {
onEnter: function (args) {
console.log(`call sub_89BF4`);
this.arg_1 = args[1];
console.log("sub_89BF4 args[1]", hexdump(args[1].readByteArray(args[2].toUInt32())))
console.log("sub_89BF4 args[2]", args[2])
},
onLeave: function (retval) {
console.log("sub_89BF4 retval", hexdump(this.arg_1));
}
});
}
freeze_funcs();
inline_hook();
call_getByte();
// setTimeout(() => {
// getByte_LogArgs();
// }, 500);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment