if(Java.available){
//java打印堆栈调用方法
function printStack(str_tag) {
var Exception= Java.use("java.lang.Exception");
var ins = Exception.$new("Exception");
var straces = ins.getStackTrace();
if (undefined == straces || null == straces)
{
return;
}
//console.log("=============================" + str_tag + " Stack strat=======================");
//console.log("");
for (var i = 0; i < straces.length; i++)
{
var str = " " + straces[i].toString();
console.log(str);
}
//console.log("");
//console.log("=============================" + str_tag + " Stack end=======================\r\n");
Exception.$dispose();
}
// jstring, jbytearray 输出
function jstring2Str(jstring) {
var ret;
Java.perform(function() {
var String = Java.use("java.lang.String");
ret = Java.cast(jstring, String);
});
return ret;
}
function jbyteArray2Array(jbyteArray) {
var ret;
Java.perform(function() {
var b = Java.use('[B');
var buffer = Java.cast(jbyteArray, b);
ret = Java.array('byte', buffer);
});
return ret;
}
//bytes2Hex
function bytes2Hex(arr) {
var str = "[";
for (var i = 0; i < arr.length; i++) {
var z = parseInt(arr[i]);
if (z < 0) z = 255 + z;
var tmp = z.toString(16);
if (tmp.length == 1) {
tmp = "0" + tmp;
}
str = str + " " + tmp;
}
return (str + " ]").toUpperCase();
}
//bytes2String
function bytes2String(arr) {
if(typeof arr === 'string') {
return arr;
}
var str = '',
_arr = arr;
for(var i = 0; i < _arr.length; i++) {
var one = _arr[i].toString(2),
v = one.match(/^1+?(?=0)/);
if(v && one.length == 8) {
var bytesLength = v[0].length;
var store = _arr[i].toString(2).slice(7 - bytesLength);
for(var st = 1; st < bytesLength; st++) {
store += _arr[st + i].toString(2).slice(2);
}
try {
str += String.fromCharCode(parseInt(store, 2));
} catch (error) {
str += parseInt(store, 2).toString();
console.log(error);
}
i += bytesLength - 1;
} else {
try {
str += String.fromCharCode(_arr[i]);
} catch (error) {
str += parseInt(store, 2).toString();
console.log(error);
}
}
}
return str;
}
//输出类所有方法名
function enumMethods(targetClass) {
var ret;
Java.perform(function() {
var hook = Java.use(targetClass);
var ret = hook.class.getDeclaredMethods();
ret.forEach(function(s) {
console.log(s);
})
})
return ret;
}
//hook 所有重载函数
function hookAllOverloads(targetClass, targetMethod) {
Java.perform(function () {
var targetClassMethod = targetClass + '.' + targetMethod;
var hook = Java.use(targetClass);
var overloadCount = hook[targetMethod].overloads.length;
for (var i = 0; i < overloadCount; i++) {
hook[targetMethod].overloads[i].implementation = function() {
var retval = this[targetMethod].apply(this, arguments);
//这里可以打印结果和参数
return retval;
}
}
});
}
//输出 byte[] 等 java 对象
function jobj2Str(jobject) {
var ret = JSON.stringify(jobject);
return ret;
}
//dump 地址
function dumpAddr(address, length) {
length = length || 1024;
console.log(hexdump(address, {
offset: 0,
length: length,
header: true,
ansi: false
}));
}
//ArrayBuffer 转换
function ab2Hex(buffer) {
var arr = Array.prototype.map.call(new Uint8Array(buffer), function (x) {return ('00' + x.toString(16)).slice(-2)}).join(" ").toUpperCase();
return "[" + arr + "]";
}
function ab2Str(buffer) {
return String.fromCharCode.apply(null, new Uint8Array(buffer));
}
//获取类型
function getParamType(obj) {
return obj == null ? String(obj) : Object.prototype.toString.call(obj).replace(/\[object\s+(\w+)\]/i, "$1") || "object";
}
//Hook 函数的参数为 map 等特殊类型
//方法1
var HashMap = Java.use('java.util.HashMap');
var ShufferMap = Java.use('com.xx.app.ShufferMap');
ShufferMap.show.implementation = function (map) {
var hm = HashMap.$new();
hm.put("user","dajianbang");
hm.put("pass","87654321");
hm.put("code","123456");
return this.show(hm);
}
//方法2 打印 map
var ShufferMap = Java.use("com.xx.app.ShufferMap");
console.log(ShufferMap);
ShufferMap.show.implementation = function(map){
console.log(JSON.stringify(map));
//Java map的遍历
// var key = map.keySet();
// var it = key.iterator();
// var result = "";
// while(it.hasNext()){
// var keystr = it.next();
// var valuestr = map.get(keystr);
// result += valuestr;
// }
// console.log(result);
// return result;
map.put("pass", "wawa");
map.put("guanwang", "666");
var retval = this.show(map);
console.log(retval);
return retval;
}
//打印[Ljava.lang.String; 数组 [Ljava.lang.String;
var ArrayClz = Java.use("java.lang.reflect.Array");
var len = ArrayClz.getLength(arg4);
for(let i=0;i!=len;i++){
console.log("arg4 -> "+ArrayClz.get(arg4,i).toString());
}
//遍历list
function printList(mapClz) {
//var key = mapClz.keySet();
var it = mapClz.iterator();
while(it.hasNext()){
var keystr = it.next();
//var valuestr = mapClz.get(keystr);
//result += valuestr;
console.log("list:"+keystr);
}
}
//主动调用函数
Java.choose("com.xx.xx.xx.xx",{
onMatch: function(instance){
instance.function();
},
onComplete: function(){
}
});
//遍历成员及函数
var members = CronetHttpURLConnection.class.getDeclaredFields();
console.log("CronetHttpURLConnection output "+this.getOutputStream())
members.forEach(function(member) {
//
console.log("member: ", member);
});
//修改静态变量
var LoginActivity3 = Java.use("com.xx.xx.xx.xx");
// 设置变量值后面必须加 `.value` 才能设置
LoginActivity3.static_bool_var.value = true;
//修改 动态变量
// 动态变量必须 choose 找到示例才能操作
Java.choose("com.xx.xx.xx.xx",{
onMatch: function(instance){
// 设置变量值后面必须加 `.value` 才能设置
instance.bool_var.value = true;
// 注意! 如果动态变量名与函数名重名了,就需要在前面加 _ 下划线,如下:
instance._same_name_bool_var.value = true;
},
onComplete: function(){
}
});
//https://www.zhangkunzhi.com/index.php/archives/3/ 具体参考
Java.perform(function()
{
//枚举所有的加载模块
var process_Obj_Module_Arr = Process.enumerateModules();
for(var i = 0; i < process_Obj_Module_Arr.length; i++) {
console.log("",process_Obj_Module_Arr[i].name);
}
console.log("hook c start");
var str_name_so = "libc.so";
var str_name_func = "fgets";
//hook 构造函数
var javaUri = Java.use("java.net.URL");
javaUri.$init.overload("java.lang.String").implementation=function(Stringclass1){
printStack("douyin");
console.log("hook java String -> "+Stringclass1);
}
//打印[Ljava.lang.String; 数组
var ArrayClz = Java.use("java.lang.reflect.Array");
var len = ArrayClz.getLength(arg4);
for(let i=0;i!=len;i++){
console.log("arg4 -> "+ArrayClz.get(arg4,i).toString());
}
//类转换
var retrofit2 = Java.use("com.bytedance.retrofit2.CallServerInterceptor");
var retrofitcb = Java.use("com.bytedance.retrofit2.c.b"); //om.bytedance.retrofit2.c.a$a 为基类
retrofit2.intercept.overload('com.bytedance.retrofit2.c.a$a').implementation = function(arg)
{
retrofitcb = arg;
console.log("retrofit2 intercept.url -> ",retrofitcb.a().getUrl());
return this.intercept(arg)
}
//********************************hook native*********************************//
//hook export function //hook 导出函数
var func_ptr = Module.findExportByName(str_name_so , str_name_func);
if (null == func_ptr)
{
console.log(str_name_func + " point is null");
return;
}
Interceptor.attach(func_ptr,
{
onEnter: function(args)
{
print_c_stack(this.context, str_name_func);
},
onLeave:function(retval)
{
}
});
//hook 地址 打印内存
var offset = 0x000428BC;
var nativelibModule = Process.findModuleByName("libnative-lib.so");
var func_addr = nativelibModule.base.add(offset).add(1);
Interceptor.attach(func_addr,{
onEnter(args){
this.arg1 = args[1];
this.arg0 = args[0];
console.log("hookMD5 onEnter arg0===> ",ptr(args[0]).readUtf8String());
// console.log("onEnter arg1===> ",hexdump(ptr(args[1])));
},
onLeave(retval){
// console.log("onLeave arg0===> ",hexdump(ptr(this.arg0)));
// ArrayBuffer
var arrayBuffer = ptr(this.arg1).readByteArray(16);
console.log("hookMD5 result->", arrayBuffer);
// var buffer = Java.array('byte', bytes);
// var ByteString = Java.use("com.android.okhttp.okio.ByteString");
// console.log("result->", bytes);
//console.log("onLeave arg1===> ",);
}
})
//将函数地址定义成一个函数能在js中进行调用#
let so_addr = Module.findBaseAddress('libxiaowei.so');
let encrypt_addr = so_addr.add(0x42B0);
//returnType是函数的返回类型(const char*)
//它这么定义的:new NativeFunction(address, returnType, argTypes[, abi])
//参数 address,表示需要构造的函数在内存中的地址,returnType是函数的返回类型(const char*),不过frida中不用这个,需要使用 pointer argTypes 参数
let encrypt_fun = new NativeFunction(encrypt_addr, 'pointer', ['pointer']);
let cstring = Memory.allocUtf8String(str);
let result = encrypt_fun(cstring);
// function main()
// {
// Java.perform(function ()
// {
var aes_addr = Module.findExportByName("libJNIEncrypt.so","AES_128_ECB_PKCS5Padding_Decrypt");
var aes_128 = new NativeFunction(aes_addr , 'pointer', ['pointer', 'pointer']);
var encry_text = Memory.allocUtf8String("9YuQ2dk8CSaCe7DTAmaqAA==");
var key = Memory.allocUtf8String('thisisatestkey==');
console.log("The result is: ",Memory.readCString(aes_128(encry_text ,key )));
// });
// }
//setImmediate(main)
//将函数地址定义成一个函数能在js中进行调用 end
//打印c堆栈 print_c_stack(this.context,"logToSttring");
//context 这里传入this.context
//str_arg 这里传入堆栈显示时展示的标签
function print_c_stack(context, str_tag)
{
console.log('');
console.log("=============================" + str_tag + " Stack strat=======================");
console.log(Thread.backtrace(context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n'));
console.log("=============================" + str_tag + " Stack end =======================");
}
//打印地址的内容
//而读取const char* 类型的数据需要使用:readCString
function print_str(addr){
var base_hello_jni = Module.findBaseAddress("libhello-jni.so");
if(base_hello_jni){
// base_hello_jni是一个指针, 指针需要使用.add方法, 直接用运算符是会出错的
var addr_str = base_hello_jni.add(addr);
console.log("addr ",addr_str," add_str",ptr(addr_str).readCString());
}
}
//打印c++成员
function hunkc()
{
var moduleso = Module.findBaseAddress("libavmdl.so");
if(moduleso == null || moduleso < 0)
{
setTimeout(hunkc,500);
return;
}
//logToSttring 日志
Interceptor.attach(Module.findExportByName("libavmdl.so" , "_ZN3com2ss3ttm11medialoader17AVMDLReplyTaskLog12logToSttringEv"),{
onEnter: function(args) {
//对象打印c++ 成员
var obj_ptr = ptr(args[0]);
//Process.pointerSize = 4
var i=9
console.log("task_type:", Memory.readInt( obj_ptr.add(2 * Process.pointerSize) ))
console.log("raw_key:", Memory.readCString( Memory.readPointer( obj_ptr.add(9 * Process.pointerSize) ) ))
},
onLeave:function(retval){
console.log("hook logToSttring ret "+Memory.readCString(retval));
}
});
}
setTimeout(hunkc,0);
//frida调用so算法
//参数 address,表示需要构造的函数在内存中的地址,returnType是函数的返回类型(const char*),不过frida中不用这个,需要使用 pointer,所以构造出来是这样的:
//var aes_128 = new NativeFunction(aes_addr , 'pointer', ['pointer', 'pointer']);
//现在基本思路都差不多了,写成的代码是这样的:
function main(){
Java.perform(function ()
{
var aes_addr = Module.findExportByName("libJNIEncrypt.so","AES_128_ECB_PKCS5Padding_Decrypt");
var aes_128 = new NativeFunction(aes_addr , 'pointer', ['pointer', 'pointer']);
var encry_text = Memory.allocUtf8String("9YuQ2dk8CSaCe7DTAmaqAA==");
var key = Memory.allocUtf8String('thisisatestkey==');
console.log("The result is: ",Memory.readCString(aes_128(encry_text ,key )));
});
}
setImmediate(main)
//打印hook地址的寄存器
function inline_hook(){
var base_hello_jni = Module.findBaseAddress("libhello-jni.so");
console.log(base_hello_jni);
if(base_hello_jni){
console.log("base_hello_jni",base_hello_jni);
var addr_07320 = base_hello_jni.add(0x07320);
// inline hook 和 hook函数是一样的
Interceptor.attach(addr_07320,{
onEnter:function(args){
//
// 64位: X0-X30, XZR(零寄存器) 要学汇编! 不然没法玩inline hook
console.log("addr_07320 x13",this.context.x13);
},
onLeave:function(retval){}
})
}
}
//********************************hook native end*********************************//
});
}
版权声明:本文为pengzhenghui123原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。